]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #7550 from volta-networks/fix_bfd_isis
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 Jan 2021 00:50:24 +0000 (19:50 -0500)
committerGitHub <noreply@github.com>
Wed, 20 Jan 2021 00:50:24 +0000 (19:50 -0500)
isisd: if IS-IS is configured for v6, prefer v6 bfd sessions

954 files changed:
.git-blame-ignore-revs
Makefile.am
bfdd/bfd.c
bfdd/bfd.h
bfdd/bfd_packet.c
bfdd/bfdd.c
bfdd/bfdd_cli.c
bfdd/bfdd_vty.c
bfdd/bfddp_packet.h [new file with mode: 0644]
bfdd/dplane.c [new file with mode: 0644]
bfdd/ptm_adapter.c
bfdd/subdir.am
bgpd/bgp_advertise.h
bgpd/bgp_attr.c
bgpd/bgp_attr_evpn.c
bgpd/bgp_bmp.c
bgpd/bgp_clist.c
bgpd/bgp_clist.h
bgpd/bgp_community.c
bgpd/bgp_conditional_adv.c
bgpd/bgp_damp.c
bgpd/bgp_damp.h
bgpd/bgp_debug.c
bgpd/bgp_ecommunity.c
bgpd/bgp_ecommunity.h
bgpd/bgp_evpn.c
bgpd/bgp_evpn.h
bgpd/bgp_evpn_mh.c
bgpd/bgp_evpn_mh.h
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_flowspec_util.c
bgpd/bgp_flowspec_vty.c
bgpd/bgp_fsm.c
bgpd/bgp_label.c
bgpd/bgp_labelpool.c
bgpd/bgp_labelpool.h
bgpd/bgp_lcommunity.c
bgpd/bgp_lcommunity.h
bgpd/bgp_main.c
bgpd/bgp_memory.c
bgpd/bgp_memory.h
bgpd/bgp_mplsvpn.c
bgpd/bgp_nb.c
bgpd/bgp_nb.h
bgpd/bgp_nb_config.c
bgpd/bgp_network.c
bgpd/bgp_nht.c
bgpd/bgp_nht.h
bgpd/bgp_open.c
bgpd/bgp_open.h
bgpd/bgp_packet.c
bgpd/bgp_packet.h
bgpd/bgp_pbr.c
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_routemap.c
bgpd/bgp_rpki.c
bgpd/bgp_script.c [new file with mode: 0644]
bgpd/bgp_script.h [new file with mode: 0644]
bgpd/bgp_table.h
bgpd/bgp_updgrp.c
bgpd/bgp_updgrp.h
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_import.c
bgpd/rfapi/rfapi_private.h
bgpd/rfapi/vnc_export_bgp.c
bgpd/subdir.am
changelog-auto.in
configure.ac
debian/control
debian/rules
doc/developer/building-frr-for-opensuse.rst [new file with mode: 0644]
doc/developer/building.rst
doc/developer/frr-release-procedure.rst
doc/developer/index.rst
doc/developer/library.rst
doc/developer/link-state.rst [new file with mode: 0644]
doc/developer/logging.rst
doc/developer/lua.rst [deleted file]
doc/developer/memtypes.rst
doc/developer/path-internals-daemon.rst [new file with mode: 0644]
doc/developer/path-internals-pcep.rst [new file with mode: 0644]
doc/developer/path-internals.rst [new file with mode: 0644]
doc/developer/path.rst [new file with mode: 0644]
doc/developer/scripting.rst [new file with mode: 0644]
doc/developer/subdir.am
doc/developer/topotests-jsontopo.rst
doc/developer/tracing.rst
doc/developer/workflow.rst
doc/figures/pcep_module_threading_overview.svg [new file with mode: 0644]
doc/user/babeld.rst
doc/user/basic.rst
doc/user/bfd.rst
doc/user/bgp.rst
doc/user/eigrpd.rst
doc/user/fabricd.rst
doc/user/filter.rst
doc/user/flowspec.rst
doc/user/index.rst
doc/user/installation.rst
doc/user/ipv6.rst
doc/user/isisd.rst
doc/user/ldpd.rst
doc/user/ospf6d.rst
doc/user/ospfd.rst
doc/user/overview.rst
doc/user/pathd.rst [new file with mode: 0644]
doc/user/pim.rst
doc/user/ripd.rst
doc/user/routemap.rst
doc/user/rpki.rst
doc/user/scripting.rst [new file with mode: 0644]
doc/user/sharp.rst
doc/user/snmp.rst
doc/user/subdir.am
doc/user/vnc.rst
doc/user/vrrp.rst
doc/user/vtysh.rst
doc/user/watchfrr.rst
doc/user/zebra.rst
eigrpd/eigrp_cli.c
eigrpd/eigrp_cli.h [new file with mode: 0644]
eigrpd/eigrp_const.h
eigrpd/eigrp_dump.c
eigrpd/eigrp_dump.h
eigrpd/eigrp_fsm.c
eigrpd/eigrp_hello.c
eigrpd/eigrp_interface.c
eigrpd/eigrp_interface.h
eigrpd/eigrp_main.c
eigrpd/eigrp_memory.c
eigrpd/eigrp_memory.h
eigrpd/eigrp_metric.c [new file with mode: 0644]
eigrpd/eigrp_metric.h [new file with mode: 0644]
eigrpd/eigrp_neighbor.c
eigrpd/eigrp_neighbor.h
eigrpd/eigrp_network.c
eigrpd/eigrp_network.h
eigrpd/eigrp_northbound.c
eigrpd/eigrp_packet.c
eigrpd/eigrp_packet.h
eigrpd/eigrp_query.c
eigrpd/eigrp_reply.c
eigrpd/eigrp_routemap.c
eigrpd/eigrp_siaquery.c
eigrpd/eigrp_siareply.c
eigrpd/eigrp_structs.h
eigrpd/eigrp_topology.c
eigrpd/eigrp_topology.h
eigrpd/eigrp_types.h [new file with mode: 0644]
eigrpd/eigrp_update.c
eigrpd/eigrp_vty.c
eigrpd/eigrp_yang.h [new file with mode: 0644]
eigrpd/eigrp_zebra.c
eigrpd/eigrpd.h
eigrpd/subdir.am
include/linux/if_bridge.h
include/linux/neighbour.h
isisd/isis_bpf.c
isisd/isis_circuit.c
isisd/isis_circuit.h
isisd/isis_cli.c
isisd/isis_ldp_sync.c
isisd/isis_ldp_sync.h
isisd/isis_lfa.c
isisd/isis_lfa.h
isisd/isis_lsp.c
isisd/isis_main.c
isisd/isis_memory.c
isisd/isis_memory.h
isisd/isis_nb.c
isisd/isis_nb.h
isisd/isis_nb_config.c
isisd/isis_route.c
isisd/isis_route.h
isisd/isis_spf.c
isisd/isis_spf.h
isisd/isis_spf_private.h
isisd/isis_tlvs.c
isisd/isis_tlvs.h
isisd/isis_zebra.c
isisd/isis_zebra.h
isisd/isisd.c
isisd/isisd.h
ldpd/adjacency.c
ldpd/hello.c
ldpd/lde.c
ldpd/lde.h
ldpd/lde_lib.c
ldpd/ldp_zebra.c
ldpd/ldpd.c
ldpd/ldpd.h
ldpd/ldpe.c
ldpd/log.c
ldpd/rlfa.c [new file with mode: 0644]
ldpd/rlfa.h [new file with mode: 0644]
ldpd/subdir.am
lib/bfd.c
lib/command.c
lib/command.h
lib/compiler.h
lib/ferr.c
lib/ferr.h
lib/filter.h
lib/filter_cli.c
lib/filter_nb.c
lib/frrlua.c
lib/frrlua.h
lib/frrscript.c [new file with mode: 0644]
lib/frrscript.h [new file with mode: 0644]
lib/hash.h
lib/ldp_sync.h
lib/lib_vty.c
lib/libfrr.c
lib/libfrr.h
lib/link_state.c [new file with mode: 0644]
lib/link_state.h [new file with mode: 0644]
lib/log.c
lib/memory.c
lib/memory.h
lib/northbound.h
lib/northbound_cli.c
lib/prefix.h
lib/route_types.pl
lib/route_types.txt
lib/routemap.c
lib/sockunion.c
lib/sockunion.h
lib/stream.c
lib/stream.h
lib/subdir.am
lib/thread.c
lib/vty.c
lib/yang.c
lib/yang.h
lib/zclient.c
lib/zclient.h
nhrpd/README.kernel
nhrpd/nhrp_cache.c
nhrpd/nhrp_interface.c
nhrpd/nhrp_nhs.c
nhrpd/nhrp_peer.c
nhrpd/nhrp_route.c
nhrpd/nhrp_shortcut.c
nhrpd/nhrp_vty.c
nhrpd/nhrpd.h
ospf6d/ospf6_abr.c
ospf6d/ospf6_abr.h
ospf6d/ospf6_area.c
ospf6d/ospf6_area.h
ospf6d/ospf6_asbr.c
ospf6d/ospf6_asbr.h
ospf6d/ospf6_interface.c
ospf6d/ospf6_intra.c
ospf6d/ospf6_lsdb.c
ospf6d/ospf6_main.c
ospf6d/ospf6_memory.c
ospf6d/ospf6_memory.h
ospf6d/ospf6_neighbor.c
ospf6d/ospf6_route.c
ospf6d/ospf6_route.h
ospf6d/ospf6_snmp.c
ospf6d/ospf6_spf.c
ospf6d/ospf6_spf.h
ospf6d/ospf6_top.c
ospf6d/ospf6_top.h
ospf6d/ospf6_zebra.c
ospf6d/ospf6d.c
ospfd/ospf_abr.c
ospfd/ospf_abr.h
ospfd/ospf_ase.c
ospfd/ospf_interface.c
ospfd/ospf_ldp_sync.c
ospfd/ospf_ldp_sync.h
ospfd/ospf_lsa.c
ospfd/ospf_route.c
ospfd/ospf_routemap.c
ospfd/ospf_snmp.c
ospfd/ospf_spf.c
ospfd/ospf_vty.c
ospfd/ospf_zebra.c
ospfd/ospfd.c
ospfd/ospfd.h
pathd/.gitignore [new file with mode: 0644]
pathd/Makefile [new file with mode: 0644]
pathd/path_cli.c [new file with mode: 0644]
pathd/path_debug.c [new file with mode: 0644]
pathd/path_debug.h [new file with mode: 0644]
pathd/path_errors.c [new file with mode: 0644]
pathd/path_errors.h [new file with mode: 0644]
pathd/path_main.c [new file with mode: 0644]
pathd/path_memory.c [new file with mode: 0644]
pathd/path_memory.h [new file with mode: 0644]
pathd/path_nb.c [new file with mode: 0644]
pathd/path_nb.h [new file with mode: 0644]
pathd/path_nb_config.c [new file with mode: 0644]
pathd/path_nb_state.c [new file with mode: 0644]
pathd/path_pcep.c [new file with mode: 0644]
pathd/path_pcep.h [new file with mode: 0644]
pathd/path_pcep_cli.c [new file with mode: 0644]
pathd/path_pcep_cli.h [new file with mode: 0644]
pathd/path_pcep_config.c [new file with mode: 0644]
pathd/path_pcep_config.h [new file with mode: 0644]
pathd/path_pcep_controller.c [new file with mode: 0644]
pathd/path_pcep_controller.h [new file with mode: 0644]
pathd/path_pcep_debug.c [new file with mode: 0644]
pathd/path_pcep_debug.h [new file with mode: 0644]
pathd/path_pcep_lib.c [new file with mode: 0644]
pathd/path_pcep_lib.h [new file with mode: 0644]
pathd/path_pcep_memory.c [new file with mode: 0644]
pathd/path_pcep_memory.h [new file with mode: 0644]
pathd/path_pcep_pcc.c [new file with mode: 0644]
pathd/path_pcep_pcc.h [new file with mode: 0644]
pathd/path_zebra.c [new file with mode: 0644]
pathd/path_zebra.h [new file with mode: 0644]
pathd/pathd.c [new file with mode: 0644]
pathd/pathd.conf.sample [new file with mode: 0644]
pathd/pathd.h [new file with mode: 0644]
pathd/subdir.am [new file with mode: 0644]
pbrd/pbr_nht.c
pbrd/pbr_vty.c
pbrd/pbr_zebra.c
pimd/pim_bsm.c
pimd/pim_bsm.h
pimd/pim_cmd.c
pimd/pim_ifchannel.c
pimd/pim_ifchannel.h
pimd/pim_igmp.c
pimd/pim_igmpv2.c
pimd/pim_igmpv2.h
pimd/pim_join.c
pimd/pim_jp_agg.c
pimd/pim_main.c
pimd/pim_mroute.c
pimd/pim_nb.c [new file with mode: 0644]
pimd/pim_nb.h [new file with mode: 0644]
pimd/pim_nb_config.c [new file with mode: 0644]
pimd/pim_nht.c
pimd/pim_rp.c
pimd/pim_rp.h
pimd/pim_static.c
pimd/pim_upstream.c
pimd/pim_version.c [deleted file]
pimd/pim_version.h [deleted file]
pimd/pim_vty.c
pimd/pim_vxlan.h
pimd/pim_zlookup.c
pimd/subdir.am
redhat/frr.spec.in
ripd/ripd.c
sharpd/sharp_globals.h
sharpd/sharp_main.c
sharpd/sharp_vty.c
sharpd/sharp_zebra.c
sharpd/sharp_zebra.h
snapcraft/snapcraft.yaml.in
staticd/static_nb.c
staticd/static_nb.h
staticd/static_nb_config.c
staticd/static_routes.c
staticd/static_routes.h
staticd/static_vty.c
staticd/static_zebra.c
tests/.gitignore
tests/bgpd/test_aspath.c
tests/bgpd/test_capability.c
tests/bgpd/test_mp_attr.c
tests/bgpd/test_mpath.c
tests/bgpd/test_packet.c
tests/bgpd/test_peer_attr.c
tests/isisd/test_common.c
tests/isisd/test_common.h
tests/isisd/test_isis_spf.c
tests/isisd/test_isis_spf.in
tests/isisd/test_isis_spf.refout
tests/isisd/test_topologies.c
tests/subdir.am
tests/topotests/Dockerfile
tests/topotests/all-protocol-startup/r1/bgpd.conf
tests/topotests/all-protocol-startup/r1/ip_nht.ref [new file with mode: 0644]
tests/topotests/all-protocol-startup/r1/ipv6_nht.ref [new file with mode: 0644]
tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref
tests/topotests/all-protocol-startup/r1/show_ip_bgp_summary.ref
tests/topotests/all-protocol-startup/test_all_protocol_startup.py
tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py
tests/topotests/bfd-ospf-topo1/__init__.py [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/bfdd.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/ospf6d.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/ospfd.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/step1/show_ip_route.ref [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/step1/show_ipv6_route.ref [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/step2/show_bfd_peers.ref [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_healthy.ref [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt2_down.ref [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt3_down.ref [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_healthy.ref [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt2_down.ref [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt3_down.ref [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_healthy.ref [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt2_down.ref [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt3_down.ref [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt1/zebra.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt2/bfdd.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt2/ospf6d.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt2/ospfd.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt2/step2/show_bfd_peers.ref [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt2/zebra.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt3/bfdd.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt3/ospf6d.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt3/ospfd.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt3/step2/show_bfd_peers.ref [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt3/zebra.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt4/bfdd.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt4/ospf6d.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt4/ospfd.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt4/zebra.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt5/bfdd.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt5/ospf6d.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt5/ospfd.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/rt5/zebra.conf [new file with mode: 0644]
tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py [new file with mode: 0755]
tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py
tests/topotests/bfd-topo1/test_bfd_topo1.py
tests/topotests/bfd-topo2/test_bfd_topo2.py
tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py
tests/topotests/bgp-auth/R1/bgpd_multi_vrf.conf
tests/topotests/bgp-auth/R1/bgpd_vrf.conf
tests/topotests/bgp-auth/R1/zebra.conf
tests/topotests/bgp-auth/R2/zebra.conf
tests/topotests/bgp-auth/R3/zebra.conf
tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py
tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
tests/topotests/bgp-evpn-mh/test_evpn_mh.py
tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py
tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py
tests/topotests/bgp-route-map/test_route_map_topo1.py
tests/topotests/bgp-route-map/test_route_map_topo2.py
tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py
tests/topotests/bgp_community_change_update/__init__.py [new file with mode: 0644]
tests/topotests/bgp_community_change_update/c1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_community_change_update/c1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py [new file with mode: 0644]
tests/topotests/bgp_community_change_update/x1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_community_change_update/x1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_community_change_update/y1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_community_change_update/y1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_community_change_update/y2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_community_change_update/y2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_community_change_update/y3/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_community_change_update/y3/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_community_change_update/z1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_community_change_update/z1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py
tests/topotests/bgp_features/exabgp.env [new file with mode: 0644]
tests/topotests/bgp_features/peer1/exa_readpipe.py [new file with mode: 0644]
tests/topotests/bgp_features/peer1/exabgp.cfg [new file with mode: 0644]
tests/topotests/bgp_features/peer2/exa_readpipe.py [new file with mode: 0644]
tests/topotests/bgp_features/peer2/exabgp.cfg [new file with mode: 0644]
tests/topotests/bgp_features/peer3/exa_readpipe.py [new file with mode: 0644]
tests/topotests/bgp_features/peer3/exabgp.cfg [new file with mode: 0644]
tests/topotests/bgp_features/peer4/exa_readpipe.py [new file with mode: 0644]
tests/topotests/bgp_features/peer4/exabgp.cfg [new file with mode: 0644]
tests/topotests/bgp_features/r1/bgp_damp_announced.json [new file with mode: 0644]
tests/topotests/bgp_features/r1/bgp_damp_setup.json [new file with mode: 0644]
tests/topotests/bgp_features/r1/bgp_delayopen_neighbor.json [new file with mode: 0644]
tests/topotests/bgp_features/r1/bgp_delayopen_summary_established.json [new file with mode: 0644]
tests/topotests/bgp_features/r1/bgp_delayopen_summary_shutdown.json [new file with mode: 0644]
tests/topotests/bgp_features/r1/ospf6d.conf
tests/topotests/bgp_features/r1/ospf_neighbor.json
tests/topotests/bgp_features/r1/ospfd.conf
tests/topotests/bgp_features/r2/bgp_damp_announced.json [new file with mode: 0644]
tests/topotests/bgp_features/r2/bgp_damp_withdrawn.json [new file with mode: 0644]
tests/topotests/bgp_features/r2/bgp_delayopen_neighbor.json [new file with mode: 0644]
tests/topotests/bgp_features/r2/bgp_delayopen_summary_connect.json [new file with mode: 0644]
tests/topotests/bgp_features/r2/bgp_delayopen_summary_established.json [new file with mode: 0644]
tests/topotests/bgp_features/r2/bgp_delayopen_summary_shutdown.json [new file with mode: 0644]
tests/topotests/bgp_features/r2/ospf6d.conf
tests/topotests/bgp_features/r2/ospf_neighbor.json
tests/topotests/bgp_features/r2/ospfd.conf
tests/topotests/bgp_features/r3/ospf6d.conf
tests/topotests/bgp_features/r3/ospf_neighbor.json
tests/topotests/bgp_features/r3/ospfd.conf
tests/topotests/bgp_features/r4/bgp_delayopen_summary_established.json [new file with mode: 0644]
tests/topotests/bgp_features/r4/bgp_delayopen_summary_shutdown.json [new file with mode: 0644]
tests/topotests/bgp_features/r5/bgp_delayopen_neighbor.json [new file with mode: 0644]
tests/topotests/bgp_features/r5/bgp_delayopen_summary_connect.json [new file with mode: 0644]
tests/topotests/bgp_features/r5/bgp_delayopen_summary_established.json [new file with mode: 0644]
tests/topotests/bgp_features/r5/bgp_delayopen_summary_shutdown.json [new file with mode: 0644]
tests/topotests/bgp_features/test_bgp_features.py
tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py
tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py
tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/add_routes.py
tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/adjacencies.py
tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/check_routes.py
tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/cleanup_all.py
tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/add_routes.py
tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/adjacencies.py
tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py
tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py
tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/cleanup_all.py
tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/del_bgp_instances.py
tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/notification_check.py
tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py
tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py
tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py
tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py
tests/topotests/bgp_listen_on_multiple_addresses/bgp_listen_on_multiple_addresses.json [new file with mode: 0644]
tests/topotests/bgp_listen_on_multiple_addresses/test_bgp_listen_on_multiple_addresses.py [new file with mode: 0755]
tests/topotests/bgp_lu_topo1/R1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_lu_topo1/R1/labelpool.summ.json [new file with mode: 0644]
tests/topotests/bgp_lu_topo1/R1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_lu_topo1/R2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json [new file with mode: 0644]
tests/topotests/bgp_lu_topo1/R2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_lu_topo1/R3/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_lu_topo1/R3/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_lu_topo1/test_bgp_lu.py [new file with mode: 0644]
tests/topotests/bgp_multi_vrf_topo2/bgp_multi_vrf_topo2.json
tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py
tests/topotests/bgp_peer-group/__init__.py [new file with mode: 0644]
tests/topotests/bgp_peer-group/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_peer-group/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_peer-group/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_peer-group/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_peer-group/r3/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_peer-group/r3/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_peer-group/test_bgp_peer-group.py [new file with mode: 0644]
tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py
tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py
tests/topotests/bgp_rfapi_basic_sanity/scripts/add_routes.py
tests/topotests/bgp_rfapi_basic_sanity/scripts/check_close.py
tests/topotests/bgp_rfapi_basic_sanity/scripts/check_routes.py
tests/topotests/bgp_rfapi_basic_sanity/scripts/check_timeout.py
tests/topotests/bgp_rfapi_basic_sanity/scripts/cleanup_all.py
tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py
tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py
tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py
tests/topotests/docker/frr-topotests.sh
tests/topotests/eigrp-topo1/test_eigrp_topo1.py
tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py
tests/topotests/isis-lfa-topo1/__init__.py [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/isisd.conf [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/step1/show_ipv6_route.ref [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/step10/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/step11/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/step12/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/step13/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/step2/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/step3/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/step4/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/step5/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/step6/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/step7/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/step8/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/step9/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt1/zebra.conf [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt2/isisd.conf [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt2/step1/show_ipv6_route.ref [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt2/zebra.conf [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt3/isisd.conf [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt3/step1/show_ipv6_route.ref [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt3/zebra.conf [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt4/isisd.conf [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt4/step1/show_ipv6_route.ref [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt4/zebra.conf [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt5/isisd.conf [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt5/step1/show_ipv6_route.ref [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt5/zebra.conf [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt6/isisd.conf [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt6/step1/show_ipv6_route.ref [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt6/zebra.conf [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt7/isisd.conf [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt7/step1/show_ipv6_route.ref [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt7/step1/show_yang_interface_isis_adjacencies.ref [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/rt7/zebra.conf [new file with mode: 0644]
tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py [new file with mode: 0755]
tests/topotests/isis-rlfa-topo1/__init__.py [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step1/show_ip_route.ref [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step1/show_ipv6_route.ref [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step10/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step10/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step2/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step2/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step3/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step3/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step4/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step4/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step5/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step5/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step6/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step6/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step7/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step7/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step8/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step8/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step9/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step9/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt2/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt2/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt2/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt3/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt3/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt3/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt4/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt4/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt4/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt5/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt5/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt5/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt6/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt6/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt6/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt7/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt7/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt7/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt8/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt8/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt8/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py [new file with mode: 0755]
tests/topotests/isis-sr-te-topo1/dst/zebra.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/bgpd.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/isisd.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/pathd.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/step1/show_mpls_table_with_candidate.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/step1/show_mpls_table_without_candidate.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/step2/show_operational_data.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/step2/show_operational_data_with_candidate.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/step3/show_operational_data_with_single_candidate.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/step3/show_operational_data_with_two_candidates.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/step4/show_mpls_table.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/step4/show_mpls_table_add_segment.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/step4/show_mpls_table_change_segment.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/step5/show_ip_route_bgp_active_srte.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/step5/show_ip_route_bgp_inactive_srte.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/step5/show_operational_data_active.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/step5/show_operational_data_inactive.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt1/zebra.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt2/isisd.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt2/zebra.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt3/isisd.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt3/zebra.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt4/isisd.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt4/zebra.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt5/isisd.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt5/zebra.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt6/bgpd.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt6/isisd.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt6/pathd.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt6/step1/show_mpls_table_with_candidate.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt6/step1/show_mpls_table_without_candidate.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt6/step2/show_operational_data.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt6/step2/show_operational_data_with_candidate.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt6/step3/show_operational_data_with_single_candidate.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt6/step3/show_operational_data_with_two_candidates.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt6/step4/show_mpls_table.ref [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/rt6/zebra.conf [new file with mode: 0644]
tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py [new file with mode: 0755]
tests/topotests/isis-sr-topo1/rt2/step10/show_ip_route.ref
tests/topotests/isis-sr-topo1/rt4/step3/show_ip_route.ref
tests/topotests/isis-sr-topo1/rt5/step10/show_ip_route.ref
tests/topotests/isis-sr-topo1/rt5/step2/show_ip_route.ref
tests/topotests/isis-sr-topo1/rt5/step3/show_ip_route.ref
tests/topotests/isis-sr-topo1/rt5/step4/show_ip_route.ref
tests/topotests/isis-sr-topo1/rt5/step5/show_ip_route.ref
tests/topotests/isis-sr-topo1/rt5/step6/show_ip_route.ref
tests/topotests/isis-sr-topo1/rt5/step7/show_ip_route.ref
tests/topotests/isis-sr-topo1/rt5/step8/show_ip_route.ref
tests/topotests/isis-sr-topo1/rt5/step9/show_ip_route.ref
tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py
tests/topotests/isis-tilfa-topo1/rt1/step1/show_mpls_table.ref
tests/topotests/isis-tilfa-topo1/rt1/step4/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt1/step4/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt1/step4/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt1/step5/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt1/step5/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt1/step5/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt1/step7/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt1/step7/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt1/step7/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt1/step8/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt1/step8/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt1/step8/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt1/step9/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt1/step9/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt1/step9/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step1/show_ip_route.ref
tests/topotests/isis-tilfa-topo1/rt2/step1/show_ipv6_route.ref
tests/topotests/isis-tilfa-topo1/rt2/step1/show_mpls_table.ref
tests/topotests/isis-tilfa-topo1/rt2/step2/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step2/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step2/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step3/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step3/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step3/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step4/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step4/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step4/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step5/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step5/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step5/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step7/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step7/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step7/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step8/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step8/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step8/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step9/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step9/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt2/step9/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step1/show_ip_route.ref
tests/topotests/isis-tilfa-topo1/rt3/step1/show_ipv6_route.ref
tests/topotests/isis-tilfa-topo1/rt3/step1/show_mpls_table.ref
tests/topotests/isis-tilfa-topo1/rt3/step4/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step4/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step4/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step5/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step5/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step5/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step6/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step6/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step6/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step7/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step7/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step7/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step8/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step8/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step8/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step9/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step9/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt3/step9/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step1/show_ip_route.ref
tests/topotests/isis-tilfa-topo1/rt4/step1/show_ipv6_route.ref
tests/topotests/isis-tilfa-topo1/rt4/step1/show_mpls_table.ref
tests/topotests/isis-tilfa-topo1/rt4/step4/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step4/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step4/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step5/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step5/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step5/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step6/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step6/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step6/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step7/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step7/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step7/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step8/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step8/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step8/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step9/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step9/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt4/step9/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt5/step1/show_ip_route.ref
tests/topotests/isis-tilfa-topo1/rt5/step1/show_ipv6_route.ref
tests/topotests/isis-tilfa-topo1/rt5/step1/show_mpls_table.ref
tests/topotests/isis-tilfa-topo1/rt5/step4/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt5/step4/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt5/step4/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt5/step5/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt5/step5/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt5/step5/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt5/step6/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step1/show_ip_route.ref
tests/topotests/isis-tilfa-topo1/rt6/step1/show_ipv6_route.ref
tests/topotests/isis-tilfa-topo1/rt6/step1/show_mpls_table.ref
tests/topotests/isis-tilfa-topo1/rt6/step4/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step4/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step4/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step5/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step5/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step5/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step6/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step6/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step6/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step7/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step7/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step7/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step8/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step8/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step8/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step9/show_ip_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step9/show_ipv6_route.ref.diff
tests/topotests/isis-tilfa-topo1/rt6/step9/show_mpls_table.ref.diff
tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py
tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
tests/topotests/isis-topo1/test_isis_topo1.py
tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf
tests/topotests/ldp-oc-acl-topo1/r1/show_ip_ospf_neighbor.json
tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf
tests/topotests/ldp-oc-acl-topo1/r2/show_ip_ospf_neighbor.json
tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf
tests/topotests/ldp-oc-acl-topo1/r3/show_ip_ospf_neighbor.json
tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf
tests/topotests/ldp-oc-acl-topo1/r4/show_ip_ospf_neighbor.json
tests/topotests/ldp-oc-topo1/r1/ospfd.conf
tests/topotests/ldp-oc-topo1/r1/show_ip_ospf_neighbor.json
tests/topotests/ldp-oc-topo1/r2/ospfd.conf
tests/topotests/ldp-oc-topo1/r2/show_ip_ospf_neighbor.json
tests/topotests/ldp-oc-topo1/r3/ospfd.conf
tests/topotests/ldp-oc-topo1/r3/show_ip_ospf_neighbor.json
tests/topotests/ldp-oc-topo1/r4/ospfd.conf
tests/topotests/ldp-oc-topo1/r4/show_ip_ospf_neighbor.json
tests/topotests/ldp-topo1/test_ldp_topo1.py
tests/topotests/ldp-vpls-topo1/r1/ospfd.conf
tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.json
tests/topotests/ldp-vpls-topo1/r2/ospfd.conf
tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.json
tests/topotests/ldp-vpls-topo1/r3/ospfd.conf
tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.json
tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.pdf
tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py
tests/topotests/lib/bgp.py
tests/topotests/lib/bgprib.py
tests/topotests/lib/common_config.py
tests/topotests/lib/lutil.py
tests/topotests/lib/ospf.py
tests/topotests/lib/pim.py [new file with mode: 0644]
tests/topotests/lib/test/test_json.py
tests/topotests/lib/topogen.py
tests/topotests/lib/topojson.py
tests/topotests/lib/topotest.py
tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py
tests/topotests/ospf-topo1/test_ospf_topo1.py
tests/topotests/ospf_basic_functionality/ospf_p2mp.json [new file with mode: 0644]
tests/topotests/ospf_basic_functionality/test_ospf_authentication.py
tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py
tests/topotests/ospf_basic_functionality/test_ospf_lan.py
tests/topotests/ospf_basic_functionality/test_ospf_nssa.py
tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py [new file with mode: 0644]
tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
tests/topotests/ospf_basic_functionality/test_ospf_single_area.py
tests/topotests/pbr-topo1/test_pbr_topo1.py
tests/topotests/pim-basic/test_pim.py
tests/topotests/pytest.ini
tests/topotests/rip-topo1/test_rip_topo1.py
tests/topotests/ripng-topo1/test_ripng_topo1.py
tests/topotests/route-scale/r1/installed.routes.json
tests/topotests/static_routing_with_ebgp/static_routes_topo1_ebgp.json [new file with mode: 0644]
tests/topotests/static_routing_with_ebgp/static_routes_topo2_ebgp.json [new file with mode: 0644]
tests/topotests/static_routing_with_ebgp/static_routes_topo3_ebgp.json [new file with mode: 0644]
tests/topotests/static_routing_with_ebgp/static_routes_topo4_ebgp.json [new file with mode: 0644]
tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py [new file with mode: 0644]
tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py [new file with mode: 0644]
tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py [new file with mode: 0644]
tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py [new file with mode: 0644]
tests/topotests/static_routing_with_ibgp/static_routes_topo1_ibgp.json [new file with mode: 0644]
tests/topotests/static_routing_with_ibgp/static_routes_topo2_ibgp.json [new file with mode: 0644]
tests/topotests/static_routing_with_ibgp/static_routes_topo3_ibgp.json [new file with mode: 0644]
tests/topotests/static_routing_with_ibgp/static_routes_topo4_ibgp.json [new file with mode: 0644]
tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py [new file with mode: 0644]
tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py [new file with mode: 0644]
tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py [new file with mode: 0644]
tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py [new file with mode: 0644]
tests/topotests/zebra_netlink/test_zebra_netlink.py
tests/topotests/zebra_rib/r1/iproute.ref [new file with mode: 0644]
tests/topotests/zebra_rib/r1/sharp_rmap.ref [new file with mode: 0644]
tests/topotests/zebra_rib/r1/static_rmap.ref [new file with mode: 0644]
tests/topotests/zebra_rib/test_zebra_rib.py
tests/zebra/test_lm_plugin.c [new file with mode: 0644]
tests/zebra/test_lm_plugin.py [new file with mode: 0644]
tests/zebra/test_lm_plugin.refout [new file with mode: 0644]
tools/etc/frr/support_bundle_commands.conf
tools/frr-reload.py
tools/frr.in
tools/frrcommon.sh.in
vrrpd/vrrp_zebra.c
vrrpd/vrrp_zebra.h
vtysh/subdir.am
vtysh/vtysh.c
vtysh/vtysh.h
vtysh/vtysh_config.c
vtysh/vtysh_main.c
yang/frr-bgp-common.yang
yang/frr-bgp.yang
yang/frr-filter.yang
yang/frr-igmp.yang
yang/frr-isisd.yang
yang/frr-nexthop.yang
yang/frr-pathd.yang [new file with mode: 0644]
yang/frr-pim.yang
yang/frr-staticd.yang
yang/frr-vrrpd.yang
yang/subdir.am
zebra/connected.c
zebra/debug_nl.c [new file with mode: 0644]
zebra/dplane_fpm_nl.c
zebra/if_netlink.c
zebra/interface.c
zebra/interface.h
zebra/kernel_netlink.c
zebra/kernel_netlink.h
zebra/kernel_socket.c
zebra/label_manager.c
zebra/label_manager.h
zebra/redistribute.c
zebra/rib.h
zebra/router-id.c
zebra/rt_netlink.c
zebra/rt_netlink.h
zebra/rule_netlink.c
zebra/sample_plugin.c
zebra/subdir.am
zebra/zapi_msg.c
zebra/zapi_msg.h
zebra/zebra_dplane.c
zebra/zebra_dplane.h
zebra/zebra_errors.c
zebra/zebra_errors.h
zebra/zebra_evpn.c
zebra/zebra_evpn_mac.c
zebra/zebra_evpn_mac.h
zebra/zebra_evpn_mh.c
zebra/zebra_evpn_mh.h
zebra/zebra_evpn_neigh.c
zebra/zebra_evpn_neigh.h
zebra/zebra_fpm.c
zebra/zebra_fpm_netlink.c
zebra/zebra_memory.c
zebra/zebra_memory.h
zebra/zebra_mpls.h
zebra/zebra_mpls_netlink.c
zebra/zebra_nhg.c
zebra/zebra_nhg.h
zebra/zebra_rib.c
zebra/zebra_rnh.c
zebra/zebra_routemap.c
zebra/zebra_routemap.h
zebra/zebra_vrf.c
zebra/zebra_vty.c
zebra/zebra_vxlan.c
zebra/zebra_vxlan.h
zebra/zebra_vxlan_private.h
zebra/zserv.c

index 61bc0ade6596beffcf2eb2c0aeeee121687922a7..c3a0fdedf08500ecd6532251c8439b020be767ff 100644 (file)
@@ -2,6 +2,7 @@
 # git blame --ignore-revs-file .git-blame-ignore-revs <...>
 # or to make it permanent
 # git config blame.ignoreRevsFile .git-blame-ignore-revs
+9fa6ec14737b94fdfb41539d96c7e4f84f3514b6
 701a01920eee5431d2052aad92aefbdf50ac2139
 bf2394f08bdc91a6cbd3784a1bfa3af3247bb06f
 0157c327715ca367d13b7f02b2981f3484ccdeeb
index b6e8a2bce81d36bb9c20e956640f0279668a67df..90c8407010b6c88faf081ae8096ab6bb63d7e480 100644 (file)
@@ -158,6 +158,7 @@ include bfdd/subdir.am
 include yang/subdir.am
 include yang/libyang_plugins/subdir.am
 include vrrpd/subdir.am
+include pathd/subdir.am
 
 include vtysh/subdir.am
 include tests/subdir.am
index cb53d96bb9c5f00c33a782211e6b495f5e51b4b2..ca4bf949556ff31d71bc826b882415ec39ac3904 100644 (file)
@@ -216,6 +216,9 @@ void bfd_session_apply(struct bfd_session *bs)
            && (bs->timers.desired_min_tx != min_tx
                || bs->timers.required_min_rx != min_rx))
                bfd_set_polling(bs);
+
+       /* Send updated information to data plane. */
+       bfd_dplane_update_session(bs);
 }
 
 void bfd_profile_remove(struct bfd_session *bs)
@@ -293,6 +296,10 @@ int bfd_session_enable(struct bfd_session *bs)
        struct vrf *vrf = NULL;
        int psock;
 
+       /* We are using data plane, we don't need software. */
+       if (bs->bdc)
+               return 0;
+
        /*
         * If the interface or VRF doesn't exist, then we must register
         * the session but delay its start.
@@ -306,6 +313,13 @@ int bfd_session_enable(struct bfd_session *bs)
                }
        }
 
+       if (!vrf_is_backend_netns() && vrf && vrf->vrf_id != VRF_DEFAULT
+           && !if_lookup_by_name(vrf->name, vrf->vrf_id)) {
+               zlog_err("session-enable: vrf interface %s not available yet",
+                        vrf->name);
+               return 0;
+       }
+
        if (bs->key.ifname[0]) {
                if (vrf)
                        ifp = if_lookup_by_name(bs->key.ifname, vrf->vrf_id);
@@ -313,14 +327,16 @@ int bfd_session_enable(struct bfd_session *bs)
                        ifp = if_lookup_by_name_all_vrf(bs->key.ifname);
                if (ifp == NULL) {
                        zlog_err(
-                               "session-enable: specified interface doesn't exists.");
+                               "session-enable: specified interface %s (VRF %s) doesn't exist.",
+                               bs->key.ifname, vrf ? vrf->name : "<all>");
                        return 0;
                }
                if (bs->key.ifname[0] && !vrf) {
                        vrf = vrf_lookup_by_id(ifp->vrf_id);
                        if (vrf == NULL) {
                                zlog_err(
-                                       "session-enable: specified VRF doesn't exists.");
+                                       "session-enable: specified VRF %u doesn't exist.",
+                                       ifp->vrf_id);
                                return 0;
                        }
                }
@@ -332,9 +348,14 @@ int bfd_session_enable(struct bfd_session *bs)
                bs->vrf = vrf_lookup_by_id(VRF_DEFAULT);
        assert(bs->vrf);
 
-       if (bs->key.ifname[0]
-           && CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
-               bs->ifp = ifp;
+       /* Assign interface pointer (if any). */
+       bs->ifp = ifp;
+
+       /* Attempt to use data plane. */
+       if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0) {
+               control_notify_config(BCM_NOTIFY_CONFIG_ADD, bs);
+               return 0;
+       }
 
        /* Sanity check: don't leak open sockets. */
        if (bs->sock != -1) {
@@ -383,6 +404,10 @@ int bfd_session_enable(struct bfd_session *bs)
  */
 void bfd_session_disable(struct bfd_session *bs)
 {
+       /* We are using data plane, we don't need software. */
+       if (bs->bdc)
+               return;
+
        /* Free up socket resources. */
        if (bs->sock != -1) {
                close(bs->sock);
@@ -393,8 +418,6 @@ void bfd_session_disable(struct bfd_session *bs)
        bfd_recvtimer_delete(bs);
        bfd_xmttimer_delete(bs);
        ptm_bfd_echo_stop(bs);
-       bs->vrf = NULL;
-       bs->ifp = NULL;
 
        /* Set session down so it doesn't report UP and disabled. */
        ptm_bfd_sess_dn(bs, BD_PATH_DOWN);
@@ -804,6 +827,9 @@ void bfd_session_free(struct bfd_session *bs)
 
        bfd_session_disable(bs);
 
+       /* Remove session from data plane if any. */
+       bfd_dplane_delete_session(bs);
+
        bfd_key_delete(bs->key);
        bfd_id_delete(bs->discrs.my_discr);
 
@@ -1267,14 +1293,18 @@ void bfd_set_echo(struct bfd_session *bs, bool echo)
                SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
 
                /* Activate/update echo receive timeout timer. */
-               bs_echo_timer_handler(bs);
+               if (bs->bdc == NULL)
+                       bs_echo_timer_handler(bs);
        } else {
                /* Check if echo mode is already disabled. */
                if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
                        return;
 
                UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
-               ptm_bfd_echo_stop(bs);
+
+               /* Deactivate timeout timer. */
+               if (bs->bdc == NULL)
+                       ptm_bfd_echo_stop(bs);
        }
 }
 
@@ -1299,6 +1329,14 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
 
                SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
 
+               /* Handle data plane shutdown case. */
+               if (bs->bdc) {
+                       bs->ses_state = PTM_BFD_ADM_DOWN;
+                       bfd_dplane_update_session(bs);
+                       control_notify(bs, bs->ses_state);
+                       return;
+               }
+
                /* Disable all events. */
                bfd_recvtimer_delete(bs);
                bfd_echo_recvtimer_delete(bs);
@@ -1319,6 +1357,14 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
 
                UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
 
+               /* Handle data plane shutdown case. */
+               if (bs->bdc) {
+                       bs->ses_state = PTM_BFD_DOWN;
+                       bfd_dplane_update_session(bs);
+                       control_notify(bs, bs->ses_state);
+                       return;
+               }
+
                /* Change and notify state change. */
                bs->ses_state = PTM_BFD_DOWN;
                control_notify(bs, bs->ses_state);
@@ -1694,7 +1740,7 @@ struct bfd_session *bfd_key_lookup(struct bfd_key key)
        inet_ntop(bs.key.family, &bs.key.peer, peer_buf,
                  sizeof(peer_buf));
        /* Handle cases where local-address is optional. */
-       if (bs.key.family == AF_INET) {
+       if (memcmp(&bs.key.local, &zero_addr, sizeof(bs.key.local))) {
                memset(&bs.key.local, 0, sizeof(bs.key.local));
                bsp = hash_lookup(bfd_key_hash, &bs);
                if (bsp) {
@@ -1743,9 +1789,12 @@ struct bfd_session *bfd_key_lookup(struct bfd_key key)
 
        /* Handle case where a context more complex ctx is present.
         * input has no iface nor local-address, but a context may
-        * exist
+        * exist.
+        *
+        * Only applies to IPv4, because IPv6 requires either
+        * local-address or interface.
         */
-       if (!bs.key.mhop) {
+       if (!bs.key.mhop && bs.key.family == AF_INET) {
                ctx.result = NULL;
                ctx.given = &bs;
                hash_walk(bfd_key_hash, &bfd_key_lookup_ignore_partial_walker,
@@ -2025,6 +2074,16 @@ static int bfd_vrf_enable(struct vrf *vrf)
                bvrf = XCALLOC(MTYPE_BFDD_VRF, sizeof(struct bfd_vrf_global));
                bvrf->vrf = vrf;
                vrf->info = (void *)bvrf;
+
+               /* Disable sockets if using data plane. */
+               if (bglobal.bg_use_dplane) {
+                       bvrf->bg_shop = -1;
+                       bvrf->bg_mhop = -1;
+                       bvrf->bg_shop6 = -1;
+                       bvrf->bg_mhop6 = -1;
+                       bvrf->bg_echo = -1;
+                       bvrf->bg_echov6 = -1;
+               }
        } else
                bvrf = vrf->info;
 
@@ -2046,25 +2105,24 @@ static int bfd_vrf_enable(struct vrf *vrf)
                if (!bvrf->bg_echov6)
                        bvrf->bg_echov6 = bp_echov6_socket(vrf);
 
-               /* Add descriptors to the event loop. */
-               if (!bvrf->bg_ev[0])
-                       thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop,
-                                       &bvrf->bg_ev[0]);
-               if (!bvrf->bg_ev[1])
-                       thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop,
-                                       &bvrf->bg_ev[1]);
+               if (!bvrf->bg_ev[0] && bvrf->bg_shop != -1)
+                       thread_add_read(master, bfd_recv_cb, bvrf,
+                                       bvrf->bg_shop, &bvrf->bg_ev[0]);
+               if (!bvrf->bg_ev[1] && bvrf->bg_mhop != -1)
+                       thread_add_read(master, bfd_recv_cb, bvrf,
+                                       bvrf->bg_mhop, &bvrf->bg_ev[1]);
                if (!bvrf->bg_ev[2] && bvrf->bg_shop6 != -1)
-                       thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop6,
-                                       &bvrf->bg_ev[2]);
+                       thread_add_read(master, bfd_recv_cb, bvrf,
+                                       bvrf->bg_shop6, &bvrf->bg_ev[2]);
                if (!bvrf->bg_ev[3] && bvrf->bg_mhop6 != -1)
-                       thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6,
-                                       &bvrf->bg_ev[3]);
-               if (!bvrf->bg_ev[4])
-                       thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo,
-                                       &bvrf->bg_ev[4]);
+                       thread_add_read(master, bfd_recv_cb, bvrf,
+                                       bvrf->bg_mhop6, &bvrf->bg_ev[3]);
+               if (!bvrf->bg_ev[4] && bvrf->bg_echo != -1)
+                       thread_add_read(master, bfd_recv_cb, bvrf,
+                                       bvrf->bg_echo, &bvrf->bg_ev[4]);
                if (!bvrf->bg_ev[5] && bvrf->bg_echov6 != -1)
-                       thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6,
-                                       &bvrf->bg_ev[5]);
+                       thread_add_read(master, bfd_recv_cb, bvrf,
+                                       bvrf->bg_echov6, &bvrf->bg_ev[5]);
        }
        if (vrf->vrf_id != VRF_DEFAULT) {
                bfdd_zclient_register(vrf->vrf_id);
index af3f92d6a8f802e6a7c6e7ecaad4f8e3d7bb74ea..7c537b40d0467c9a27773f681a8f5316bcdb921e 100644 (file)
@@ -269,6 +269,7 @@ struct bfd_session {
        struct bfd_key key;
        struct peer_label *pl;
 
+       struct bfd_dplane_ctx *bdc;
        struct sockaddr_any local_address;
        struct interface *ifp;
        struct vrf *vrf;
@@ -424,6 +425,10 @@ struct bfd_vrf_global {
        struct thread *bg_ev[6];
 };
 
+/* Forward declaration of data plane context struct. */
+struct bfd_dplane_ctx;
+TAILQ_HEAD(dplane_queue, bfd_dplane_ctx);
+
 struct bfd_global {
        int bg_csock;
        struct thread *bg_csockev;
@@ -441,7 +446,15 @@ struct bfd_global {
         */
        bool bg_shutdown;
 
+       /* Distributed BFD items. */
+       bool bg_use_dplane;
+       int bg_dplane_sock;
+       struct thread *bg_dplane_sockev;
+       struct dplane_queue bg_dplaneq;
+
        /* Debug options. */
+       /* Show distributed BFD debug messages. */
+       bool debug_dplane;
        /* Show all peer state changes events. */
        bool debug_peer_event;
        /*
@@ -742,4 +755,56 @@ void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf);
 
 int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state);
 
+/*
+ * dplane.c
+ */
+
+/**
+ * Initialize BFD data plane infrastructure for distributed BFD implementation.
+ *
+ * \param sa socket address.
+ * \param salen socket address structure length.
+ * \param client `true` means connecting socket, `false` listening socket.
+ */
+void bfd_dplane_init(const struct sockaddr *sa, socklen_t salen, bool client);
+
+/**
+ * Attempts to delegate the BFD session liveness detection to hardware.
+ *
+ * \param bs the BFD session data structure.
+ *
+ * \returns
+ * `0` on success and BFD daemon should do nothing or `-1` on failure
+ * and we should fallback to software implementation.
+ */
+int bfd_dplane_add_session(struct bfd_session *bs);
+
+/**
+ * Send new session settings to data plane.
+ *
+ * \param bs the BFD session to update.
+ */
+int bfd_dplane_update_session(const struct bfd_session *bs);
+
+/**
+ * Deletes session from data plane.
+ *
+ * \param bs the BFD session to delete.
+ *
+ * \returns `0` on success otherwise `-1`.
+ */
+int bfd_dplane_delete_session(struct bfd_session *bs);
+
+/**
+ * Asks the data plane for updated counters and update the session data
+ * structure.
+ *
+ * \param bs the BFD session that needs updating.
+ *
+ * \returns `0` on success otherwise `-1` on failure.
+ */
+int bfd_dplane_update_session_counters(struct bfd_session *bs);
+
+void bfd_dplane_show_counters(struct vty *vty);
+
 #endif /* _BFD_H_ */
index 0a71c18a42972afabf26d51d9a8dfeda552b7896..076318e6cae2857f200377fe98e64a32be434e57 100644 (file)
@@ -543,6 +543,7 @@ int bfd_recv_cb(struct thread *t)
        ifindex_t ifindex = IFINDEX_INTERNAL;
        struct sockaddr_any local, peer;
        uint8_t msgbuf[1516];
+       struct interface *ifp = NULL;
        struct bfd_vrf_global *bvrf = THREAD_ARG(t);
 
        vrfid = bvrf->vrf->vrf_id;
@@ -572,6 +573,15 @@ int bfd_recv_cb(struct thread *t)
                                     &local, &peer);
        }
 
+       /* update vrf-id because when in vrf-lite mode,
+        * the socket is on default namespace
+        */
+       if (ifindex) {
+               ifp = if_lookup_by_index(ifindex, vrfid);
+               if (ifp)
+                       vrfid = ifp->vrf_id;
+       }
+
        /* Implement RFC 5880 6.8.6 */
        if (mlen < BFD_PKT_LEN) {
                cp_debug(is_mhop, &peer, &local, ifindex, vrfid,
@@ -951,8 +961,9 @@ int bp_peer_socket(const struct bfd_session *bs)
 
        if (bs->key.ifname[0])
                device_to_bind = (const char *)bs->key.ifname;
-       else if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
-           && bs->key.vrfname[0])
+       else if ((!vrf_is_backend_netns() && bs->vrf->vrf_id != VRF_DEFAULT)
+                || ((CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
+                     && bs->key.vrfname[0])))
                device_to_bind = (const char *)bs->key.vrfname;
 
        frr_with_privs(&bglobal.bfdd_privs) {
@@ -1018,8 +1029,9 @@ int bp_peer_socketv6(const struct bfd_session *bs)
 
        if (bs->key.ifname[0])
                device_to_bind = (const char *)bs->key.ifname;
-       else if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
-           && bs->key.vrfname[0])
+       else if ((!vrf_is_backend_netns() && bs->vrf->vrf_id != VRF_DEFAULT)
+                || ((CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
+                     && bs->key.vrfname[0])))
                device_to_bind = (const char *)bs->key.vrfname;
 
        frr_with_privs(&bglobal.bfdd_privs) {
index 098e7a289e3dcfe9a09c480718574917f7be2dd2..b8a059708f21a4c4595e4e6b99b1a4d362d95149 100644 (file)
 
 #include <zebra.h>
 
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <err.h>
+
 #include "filter.h"
 #include "if.h"
 #include "vrf.h"
 
 #include "bfd.h"
 #include "bfdd_nb.h"
+#include "bfddp_packet.h"
 #include "lib/version.h"
 #include "lib/command.h"
 
@@ -129,8 +137,10 @@ FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617,
                .n_yang_modules = array_size(bfdd_yang_modules))
 
 #define OPTION_CTLSOCK 1001
+#define OPTION_DPLANEADDR 2000
 static const struct option longopts[] = {
        {"bfdctl", required_argument, NULL, OPTION_CTLSOCK},
+       {"dplaneaddr", required_argument, NULL, OPTION_DPLANEADDR},
        {0}
 };
 
@@ -160,6 +170,143 @@ const struct bfd_state_str_list state_list[] = {
        {.str = NULL},
 };
 
+static uint16_t
+parse_port(const char *str)
+{
+       char *nulbyte;
+       long rv;
+
+       errno = 0;
+       rv = strtol(str, &nulbyte, 10);
+       /* No conversion performed. */
+       if (rv == 0 && errno == EINVAL) {
+               fprintf(stderr, "invalid BFD data plane address port: %s\n",
+                       str);
+               exit(0);
+       }
+       /* Invalid number range. */
+       if ((rv <= 0 || rv >= 65535) || errno == ERANGE) {
+               fprintf(stderr, "invalid BFD data plane port range: %s\n",
+                       str);
+               exit(0);
+       }
+       /* There was garbage at the end of the string. */
+       if (*nulbyte != 0) {
+               fprintf(stderr, "invalid BFD data plane port: %s\n",
+                       str);
+               exit(0);
+       }
+
+       return (uint16_t)rv;
+}
+
+static void
+distributed_bfd_init(const char *arg)
+{
+       char *sptr, *saux;
+       bool is_client = false;
+       size_t slen;
+       socklen_t salen;
+       char addr[64];
+       char type[64];
+       union {
+               struct sockaddr_in sin;
+               struct sockaddr_in6 sin6;
+               struct sockaddr_un sun;
+       } sa;
+
+       /* Basic parsing: find ':' to figure out type part and address part. */
+       sptr = strchr(arg, ':');
+       if (sptr == NULL) {
+               fprintf(stderr, "invalid BFD data plane socket: %s\n", arg);
+               exit(1);
+       }
+
+       /* Calculate type string length. */
+       slen = (size_t)(sptr - arg);
+
+       /* Copy the address part. */
+       sptr++;
+       strlcpy(addr, sptr, sizeof(addr));
+
+       /* Copy type part. */
+       strlcpy(type, arg, slen + 1);
+
+       /* Reset address data. */
+       memset(&sa, 0, sizeof(sa));
+
+       /* Fill the address information. */
+       if (strcmp(type, "unix") == 0 || strcmp(type, "unixc") == 0) {
+               if (strcmp(type, "unixc") == 0)
+                       is_client = true;
+
+               salen = sizeof(sa.sun);
+               sa.sun.sun_family = AF_UNIX;
+               strlcpy(sa.sun.sun_path, addr, sizeof(sa.sun.sun_path));
+       } else if (strcmp(type, "ipv4") == 0 || strcmp(type, "ipv4c") == 0) {
+               if (strcmp(type, "ipv4c") == 0)
+                       is_client = true;
+
+               salen = sizeof(sa.sin);
+               sa.sin.sin_family = AF_INET;
+
+               /* Parse port if any. */
+               sptr = strchr(addr, ':');
+               if (sptr == NULL) {
+                       sa.sin.sin_port = htons(BFD_DATA_PLANE_DEFAULT_PORT);
+               } else {
+                       *sptr = 0;
+                       sa.sin.sin_port = htons(parse_port(sptr + 1));
+               }
+
+               if (inet_pton(AF_INET, addr, &sa.sin.sin_addr) != 1)
+                       errx(1, "%s: inet_pton: invalid address %s", __func__,
+                            addr);
+       } else if (strcmp(type, "ipv6") == 0 || strcmp(type, "ipv6c") == 0) {
+               if (strcmp(type, "ipv6c") == 0)
+                       is_client = true;
+
+               salen = sizeof(sa.sin6);
+               sa.sin6.sin6_family = AF_INET6;
+
+               /* Check for IPv6 enclosures '[]' */
+               sptr = &addr[0];
+               if (*sptr != '[')
+                       errx(1, "%s: invalid IPv6 address format: %s", __func__,
+                            addr);
+
+               saux = strrchr(addr, ']');
+               if (saux == NULL)
+                       errx(1, "%s: invalid IPv6 address format: %s", __func__,
+                            addr);
+
+               /* Consume the '[]:' part. */
+               slen = saux - sptr;
+               memmove(addr, addr + 1, slen);
+               addr[slen - 1] = 0;
+
+               /* Parse port if any. */
+               saux++;
+               sptr = strrchr(saux, ':');
+               if (sptr == NULL) {
+                       sa.sin6.sin6_port = htons(BFD_DATA_PLANE_DEFAULT_PORT);
+               } else {
+                       *sptr = 0;
+                       sa.sin6.sin6_port = htons(parse_port(sptr + 1));
+               }
+
+               if (inet_pton(AF_INET6, addr, &sa.sin6.sin6_addr) != 1)
+                       errx(1, "%s: inet_pton: invalid address %s", __func__,
+                            addr);
+       } else {
+               fprintf(stderr, "invalid BFD data plane socket type: %s\n",
+                       type);
+               exit(1);
+       }
+
+       /* Initialize BFD data plane listening socket. */
+       bfd_dplane_init((struct sockaddr *)&sa, salen, is_client);
+}
 
 static void bg_init(void)
 {
@@ -185,7 +332,7 @@ static void bg_init(void)
 
 int main(int argc, char *argv[])
 {
-       char ctl_path[512];
+       char ctl_path[512], dplane_addr[512];
        bool ctlsockused = false;
        int opt;
 
@@ -194,7 +341,8 @@ int main(int argc, char *argv[])
 
        frr_preinit(&bfdd_di, argc, argv);
        frr_opt_add("", longopts,
-                   "      --bfdctl       Specify bfdd control socket\n");
+                   "      --bfdctl       Specify bfdd control socket\n"
+                   "      --dplaneaddr   Specify BFD data plane address\n");
 
        snprintf(ctl_path, sizeof(ctl_path), BFDD_CONTROL_SOCKET,
                 "", "");
@@ -208,6 +356,10 @@ int main(int argc, char *argv[])
                        strlcpy(ctl_path, optarg, sizeof(ctl_path));
                        ctlsockused = true;
                        break;
+               case OPTION_DPLANEADDR:
+                       strlcpy(dplane_addr, optarg, sizeof(dplane_addr));
+                       bglobal.bg_use_dplane = true;
+                       break;
 
                default:
                        frr_help_exit(1);
@@ -248,6 +400,10 @@ int main(int argc, char *argv[])
        /* read configuration file and daemonize  */
        frr_config_fork();
 
+       /* Initialize BFD data plane listening socket. */
+       if (bglobal.bg_use_dplane)
+               distributed_bfd_init(dplane_addr);
+
        frr_run(master);
        /* NOTREACHED */
 
index ddec83397dd2d87f4780815769c5cddc1d89dff6..b9e7903613f0228f5c455d437193b305901264d1 100644 (file)
 /*
  * Prototypes.
  */
+static bool
+bfd_cli_is_single_hop(struct vty *vty)
+{
+       return strstr(VTY_CURR_XPATH, "/single-hop") != NULL;
+}
 
 /*
  * Functions.
@@ -293,6 +298,11 @@ DEFPY_YANG(
        "Expect packets with at least this TTL\n"
        "Minimum TTL expected\n")
 {
+       if (bfd_cli_is_single_hop(vty)) {
+               vty_out(vty, "%% Minimum TTL is only available for multi hop sessions.\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        if (no)
                nb_cli_enqueue_change(vty, "./minimum-ttl", NB_OP_DESTROY,
                                      NULL);
@@ -408,6 +418,11 @@ DEFPY_YANG(
        NO_STR
        "Configure echo mode\n")
 {
+       if (!bfd_cli_is_single_hop(vty)) {
+               vty_out(vty, "%% Echo mode is only available for single hop sessions.\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        nb_cli_enqueue_change(vty, "./echo-mode", NB_OP_MODIFY,
                              no ? "false" : "true");
        return nb_cli_apply_changes(vty, NULL);
@@ -431,6 +446,11 @@ DEFPY_YANG(
 {
        char value[32];
 
+       if (!bfd_cli_is_single_hop(vty)) {
+               vty_out(vty, "%% Echo mode is only available for single hop sessions.\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        snprintf(value, sizeof(value), "%ld", interval * 1000);
        nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval",
                              NB_OP_MODIFY, value);
index 837a7b7d7d66a4b036460710ea7c8e813bb1bc0a..53e23cf6c2139d2c072c659456ef72c1a002d2cd 100644 (file)
@@ -348,6 +348,11 @@ static void _display_peer_counter(struct vty *vty, struct bfd_session *bs)
 {
        _display_peer_header(vty, bs);
 
+       /* Ask data plane for updated counters. */
+       if (bfd_dplane_update_session_counters(bs) == -1)
+               zlog_debug("%s: failed to update BFD session counters (%s)",
+                          __func__, bs_to_string(bs));
+
        vty_out(vty, "\t\tControl packet input: %" PRIu64 " packets\n",
                bs->stats.rx_ctrl_pkt);
        vty_out(vty, "\t\tControl packet output: %" PRIu64 " packets\n",
@@ -369,6 +374,11 @@ static struct json_object *__display_peer_counters_json(struct bfd_session *bs)
 {
        struct json_object *jo = _peer_json_header(bs);
 
+       /* Ask data plane for updated counters. */
+       if (bfd_dplane_update_session_counters(bs) == -1)
+               zlog_debug("%s: failed to update BFD session counters (%s)",
+                          __func__, bs_to_string(bs));
+
        json_object_int_add(jo, "control-packet-input", bs->stats.rx_ctrl_pkt);
        json_object_int_add(jo, "control-packet-output", bs->stats.tx_ctrl_pkt);
        json_object_int_add(jo, "echo-packet-input", bs->stats.rx_echo_pkt);
@@ -748,6 +758,28 @@ DEFPY(bfd_show_peers_brief, bfd_show_peers_brief_cmd,
        return CMD_SUCCESS;
 }
 
+DEFPY(show_bfd_distributed, show_bfd_distributed_cmd,
+      "show bfd distributed",
+      SHOW_STR
+      "Bidirection Forwarding Detection\n"
+      "Show BFD data plane (distributed BFD) statistics\n")
+{
+       bfd_dplane_show_counters(vty);
+       return CMD_SUCCESS;
+}
+
+DEFPY(
+       bfd_debug_distributed, bfd_debug_distributed_cmd,
+       "[no] debug bfd distributed",
+       NO_STR
+       DEBUG_STR
+       "Bidirection Forwarding Detection\n"
+       "BFD data plane (distributed BFD) debugging\n")
+{
+       bglobal.debug_dplane = !no;
+       return CMD_SUCCESS;
+}
+
 DEFPY(
        bfd_debug_peer, bfd_debug_peer_cmd,
        "[no] debug bfd peer",
@@ -888,6 +920,8 @@ DEFUN_NOSH(show_debugging_bfd,
           "BFD daemon\n")
 {
        vty_out(vty, "BFD debugging status:\n");
+       if (bglobal.debug_dplane)
+               vty_out(vty, "  Distributed BFD debugging is on.\n");
        if (bglobal.debug_peer_event)
                vty_out(vty, "  Peer events debugging is on.\n");
        if (bglobal.debug_zebra)
@@ -919,6 +953,11 @@ static int bfdd_write_config(struct vty *vty)
        struct lyd_node *dnode;
        int written = 0;
 
+       if (bglobal.debug_dplane) {
+               vty_out(vty, "debug bfd distributed\n");
+               written = 1;
+       }
+
        if (bglobal.debug_peer_event) {
                vty_out(vty, "debug bfd peer\n");
                written = 1;
@@ -951,12 +990,15 @@ void bfdd_vty_init(void)
        install_element(ENABLE_NODE, &bfd_show_peers_cmd);
        install_element(ENABLE_NODE, &bfd_show_peer_cmd);
        install_element(ENABLE_NODE, &bfd_show_peers_brief_cmd);
+       install_element(ENABLE_NODE, &show_bfd_distributed_cmd);
        install_element(ENABLE_NODE, &show_debugging_bfd_cmd);
 
+       install_element(ENABLE_NODE, &bfd_debug_distributed_cmd);
        install_element(ENABLE_NODE, &bfd_debug_peer_cmd);
        install_element(ENABLE_NODE, &bfd_debug_zebra_cmd);
        install_element(ENABLE_NODE, &bfd_debug_network_cmd);
 
+       install_element(CONFIG_NODE, &bfd_debug_distributed_cmd);
        install_element(CONFIG_NODE, &bfd_debug_peer_cmd);
        install_element(CONFIG_NODE, &bfd_debug_zebra_cmd);
        install_element(CONFIG_NODE, &bfd_debug_network_cmd);
diff --git a/bfdd/bfddp_packet.h b/bfdd/bfddp_packet.h
new file mode 100644 (file)
index 0000000..8865bae
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * BFD Data Plane protocol messages header.
+ *
+ * Copyright (C) 2020 Network Device Education Foundation, Inc. ("NetDEF")
+ *                    Rafael F. Zalamena
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the “Software”), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 OR COPYRIGHT HOLDERS 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.
+ */
+
+/**
+ * \file bfddp_packet.h
+ */
+#ifndef BFD_DP_PACKET_H
+#define BFD_DP_PACKET_H
+
+#include <netinet/in.h>
+
+#include <stdint.h>
+
+/*
+ * Protocol definitions.
+ */
+
+/**
+ * BFD protocol version as defined in RFC5880 Section 4.1 Generic BFD Control
+ * Packet Format.
+ */
+#define BFD_PROTOCOL_VERSION 1
+
+/** Default data plane port. */
+#define BFD_DATA_PLANE_DEFAULT_PORT 50700
+
+/** BFD single hop UDP port, as defined in RFC 5881 Section 4. Encapsulation. */
+#define BFD_SINGLE_HOP_PORT 3784
+
+/** BFD multi hop UDP port, as defined in RFC 5883 Section 5. Encapsulation. */
+#define BFD_MULTI_HOP_PORT 4784
+
+/** Default slow start multiplier. */
+#define SLOWSTART_DMULT 3
+/** Default slow start transmission speed. */
+#define SLOWSTART_TX 1000000u
+/** Default slow start receive speed. */
+#define SLOWSTART_RX 1000000u
+/** Default slow start echo receive speed. */
+#define SLOWSTART_ERX 0u
+
+/*
+ * BFD single hop source UDP ports. As defined in RFC 5881 Section 4.
+ * Encapsulation.
+ */
+#define BFD_SOURCE_PORT_BEGIN 49152
+#define BFD_SOURCE_PORT_END 65535
+
+/** BFD data plane protocol version. */
+#define BFD_DP_VERSION 1
+
+/** BFD data plane message types. */
+enum bfddp_message_type {
+       /** Ask for BFD daemon or data plane for echo packet. */
+       ECHO_REQUEST = 0,
+       /** Answer a ECHO_REQUEST packet. */
+       ECHO_REPLY = 1,
+       /** Add or update BFD peer session. */
+       DP_ADD_SESSION = 2,
+       /** Delete BFD peer session. */
+       DP_DELETE_SESSION = 3,
+       /** Tell BFD daemon state changed: timer expired or session down. */
+       BFD_STATE_CHANGE = 4,
+
+       /** Ask for BFD session counters. */
+       DP_REQUEST_SESSION_COUNTERS = 5,
+       /** Tell BFD daemon about counters values. */
+       BFD_SESSION_COUNTERS = 6,
+};
+
+/**
+ * `ECHO_REQUEST`/`ECHO_REPLY` data payload.
+ *
+ * Data plane might use whatever precision it wants for `dp_time`
+ * field, however if you want to be able to tell the delay between
+ * data plane packet send and BFD daemon packet processing you should
+ * use `gettimeofday()` and have the data plane clock synchronized with
+ * BFD daemon (not a problem if data plane runs in the same system).
+ *
+ * Normally data plane will only check the time stamp it sent to determine
+ * the whole packet trip time.
+ */
+struct bfddp_echo {
+       /** Filled by data plane. */
+       uint64_t dp_time;
+       /** Filled by BFD daemon. */
+       uint64_t bfdd_time;
+};
+
+
+/** BFD session flags. */
+enum bfddp_session_flag {
+       /** Set when using multi hop. */
+       SESSION_MULTIHOP = (1 << 0),
+       /** Set when using demand mode. */
+       SESSION_DEMAND = (1 << 1),
+       /** Set when using cbit (Control Plane Independent). */
+       SESSION_CBIT = (1 << 2),
+       /** Set when using echo mode. */
+       SESSION_ECHO = (1 << 3),
+       /** Set when using IPv6. */
+       SESSION_IPV6 = (1 << 4),
+       /** Set when using passive mode. */
+       SESSION_PASSIVE = (1 << 5),
+       /** Set when session is administrative down. */
+       SESSION_SHUTDOWN = (1 << 6),
+};
+
+/**
+ * `DP_ADD_SESSION`/`DP_DELETE_SESSION` data payload.
+ *
+ * `lid` is unique in BFD daemon so it might be used as key for data
+ * structures lookup.
+ */
+struct bfddp_session {
+       /** Important session flags. \see bfddp_session_flag. */
+       uint32_t flags;
+       /**
+        * Session source address.
+        *
+        * Check `flags` field for `SESSION_IPV6` before using as IPv6.
+        */
+       struct in6_addr src;
+       /**
+        * Session destination address.
+        *
+        * Check `flags` field for `SESSION_IPV6` before using as IPv6.
+        */
+       struct in6_addr dst;
+
+       /** Local discriminator. */
+       uint32_t lid;
+       /**
+        * Minimum desired transmission interval (in microseconds) without
+        * jitter.
+        */
+       uint32_t min_tx;
+       /**
+        * Required minimum receive interval rate (in microseconds) without
+        * jitter.
+        */
+       uint32_t min_rx;
+       /**
+        * Required minimum echo receive interval rate (in microseconds)
+        * without jitter.
+        */
+       uint32_t min_echo_rx;
+       /** Amount of milliseconds to wait before starting the session */
+       uint32_t hold_time;
+
+       /** Minimum TTL. */
+       uint8_t ttl;
+       /** Detection multiplier. */
+       uint8_t detect_mult;
+       /** Reserved / zeroed. */
+       uint16_t zero;
+
+       /** Interface index (set to `0` when unavailable). */
+       uint32_t ifindex;
+       /** Interface name (empty when unavailable). */
+       char ifname[64];
+
+       /* TODO: missing authentication. */
+};
+
+/** BFD packet state values as defined in RFC 5880, Section 4.1. */
+enum bfd_state_value {
+       /** Session is administratively down. */
+       STATE_ADMINDOWN = 0,
+       /** Session is down or went down. */
+       STATE_DOWN = 1,
+       /** Session is initializing. */
+       STATE_INIT = 2,
+       /** Session is up. */
+       STATE_UP = 3,
+};
+
+/** BFD diagnostic field values as defined in RFC 5880, Section 4.1. */
+enum bfd_diagnostic_value {
+       /** Nothing was diagnosed. */
+       DIAG_NOTHING = 0,
+       /** Control detection time expired. */
+       DIAG_CONTROL_EXPIRED = 1,
+       /** Echo function failed. */
+       DIAG_ECHO_FAILED = 2,
+       /** Neighbor signaled down. */
+       DIAG_DOWN = 3,
+       /** Forwarding plane reset. */
+       DIAG_FP_RESET = 4,
+       /** Path down. */
+       DIAG_PATH_DOWN = 5,
+       /** Concatenated path down. */
+       DIAG_CONCAT_PATH_DOWN = 6,
+       /** Administratively down. */
+       DIAG_ADMIN_DOWN = 7,
+       /** Reverse concatenated path down. */
+       DIAG_REV_CONCAT_PATH_DOWN = 8,
+};
+
+/** BFD remote state flags. */
+enum bfd_remote_flags {
+       /** Control Plane Independent bit. */
+       RBIT_CPI = (1 << 0),
+       /** Demand mode bit. */
+       RBIT_DEMAND = (1 << 1),
+       /** Multipoint bit. */
+       RBIT_MP = (1 << 2),
+};
+
+/**
+ * `BFD_STATE_CHANGE` data payload.
+ */
+struct bfddp_state_change {
+       /** Local discriminator. */
+       uint32_t lid;
+       /** Remote discriminator. */
+       uint32_t rid;
+       /** Remote configurations/bits set. \see bfd_remote_flags. */
+       uint32_t remote_flags;
+       /** Remote minimum desired transmission interval. */
+       uint32_t desired_tx;
+       /** Remote minimum receive interval. */
+       uint32_t required_rx;
+       /** Remote minimum echo receive interval. */
+       uint32_t required_echo_rx;
+       /** Remote state. \see bfd_state_values.*/
+       uint8_t state;
+       /** Remote diagnostics (if any) */
+       uint8_t diagnostics;
+       /** Remote detection multiplier. */
+       uint8_t detection_multiplier;
+};
+
+/**
+ * BFD control packet state bits definition.
+ */
+enum bfddp_control_state_bits {
+       /** Used to request connection establishment signal. */
+       STATE_POLL_BIT = (1 << 5),
+       /** Finalizes the connection establishment signal. */
+       STATE_FINAL_BIT = (1 << 4),
+       /** Signalizes that forward plane doesn't depend on control plane. */
+       STATE_CPI_BIT = (1 << 3),
+       /** Signalizes the use of authentication. */
+       STATE_AUTH_BIT = (1 << 2),
+       /** Signalizes that peer is using demand mode. */
+       STATE_DEMAND_BIT = (1 << 1),
+       /** Used in RFC 8562 implementation. */
+       STATE_MULTI_BIT = (1 << 0),
+};
+
+/**
+ * BFD control packet.
+ *
+ * As defined in 'RFC 5880 Section 4.1 Generic BFD Control Packet Format'.
+ */
+struct bfddp_control_packet {
+       /** (3 bits version << 5) | (5 bits diag). */
+       uint8_t version_diag;
+       /**
+        * (2 bits state << 6) | (6 bits flags)
+        *
+        * \see bfd_state_value, bfddp_control_state_bits.
+        */
+       uint8_t state_bits;
+       /** Detection multiplier. */
+       uint8_t detection_multiplier;
+       /** Packet length in bytes. */
+       uint8_t length;
+       /** Our discriminator. */
+       uint32_t local_id;
+       /** Remote system discriminator. */
+       uint32_t remote_id;
+       /** Desired minimum send interval in microseconds. */
+       uint32_t desired_tx;
+       /** Desired minimum receive interval in microseconds. */
+       uint32_t required_rx;
+       /** Desired minimum echo receive interval in microseconds. */
+       uint32_t required_echo_rx;
+};
+
+/**
+ * The protocol wire message header structure.
+ */
+struct bfddp_message_header {
+       /** Protocol version format. \see BFD_DP_VERSION. */
+       uint8_t version;
+       /** Reserved / zero field. */
+       uint8_t zero;
+       /** Message contents type. \see bfddp_message_type. */
+       uint16_t type;
+       /**
+        * Message identification (to pair request/response).
+        *
+        * The ID `0` is reserved for asynchronous messages (e.g. unrequested
+        * messages).
+        */
+       uint16_t id;
+       /** Message length. */
+       uint16_t length;
+};
+
+/**
+ * Data plane session counters request.
+ *
+ * Message type: `DP_REQUEST_SESSION_COUNTERS`.
+ */
+struct bfddp_request_counters {
+       /** Session local discriminator. */
+       uint32_t lid;
+};
+
+/**
+ * BFD session counters reply.
+ *
+ * Message type: `BFD_SESSION_COUNTERS`.
+ */
+struct bfddp_session_counters {
+       /** Session local discriminator. */
+       uint32_t lid;
+
+       /** Control packet bytes input. */
+       uint64_t control_input_bytes;
+       /** Control packets input. */
+       uint64_t control_input_packets;
+       /** Control packet bytes output. */
+       uint64_t control_output_bytes;
+       /** Control packets output. */
+       uint64_t control_output_packets;
+
+       /** Echo packet bytes input. */
+       uint64_t echo_input_bytes;
+       /** Echo packets input. */
+       uint64_t echo_input_packets;
+       /** Echo packet bytes output. */
+       uint64_t echo_output_bytes;
+       /** Echo packets output. */
+       uint64_t echo_output_packets;
+};
+
+/**
+ * The protocol wire messages structure.
+ */
+struct bfddp_message {
+       /** Message header. \see bfddp_message_header. */
+       struct bfddp_message_header header;
+
+       /** Message payload. \see bfddp_message_type. */
+       union {
+               struct bfddp_echo echo;
+               struct bfddp_session session;
+               struct bfddp_state_change state;
+               struct bfddp_control_packet control;
+               struct bfddp_request_counters counters_req;
+               struct bfddp_session_counters session_counters;
+       } data;
+};
+
+#endif /* BFD_DP_PACKET_H */
diff --git a/bfdd/dplane.c b/bfdd/dplane.c
new file mode 100644 (file)
index 0000000..b8f0aad
--- /dev/null
@@ -0,0 +1,1199 @@
+/*
+ * BFD data plane implementation (distributed BFD).
+ *
+ * Copyright (C) 2020 Network Device Education Foundation, Inc. ("NetDEF")
+ *                    Rafael Zalamena
+ *
+ * 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 <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#ifdef __FreeBSD__
+#include <sys/endian.h>
+#else
+#include <endian.h>
+#endif /* __FreeBSD__ */
+
+#include <errno.h>
+#include <time.h>
+
+#include "lib/hook.h"
+#include "lib/network.h"
+#include "lib/printfrr.h"
+#include "lib/stream.h"
+#include "lib/thread.h"
+
+#include "bfd.h"
+#include "bfddp_packet.h"
+
+#include "lib/openbsd-queue.h"
+
+DEFINE_MTYPE_STATIC(BFDD, BFDD_DPLANE_CTX, "Data plane client allocated memory")
+
+/** Data plane client socket buffer size. */
+#define BFD_DPLANE_CLIENT_BUF_SIZE 8192
+
+struct bfd_dplane_ctx {
+       /** Client file descriptor. */
+       int sock;
+       /** Is this a connected or accepted? */
+       bool client;
+       /** Is the socket still connecting? */
+       bool connecting;
+       /** Client/server address. */
+       union {
+               struct sockaddr sa;
+               struct sockaddr_in sin;
+               struct sockaddr_in6 sin6;
+               struct sockaddr_un sun;
+       } addr;
+       /** Address length. */
+       socklen_t addrlen;
+       /** Data plane current last used ID. */
+       uint16_t last_id;
+
+       /** Input buffer data. */
+       struct stream *inbuf;
+       /** Output buffer data. */
+       struct stream *outbuf;
+       /** Input event data. */
+       struct thread *inbufev;
+       /** Output event data. */
+       struct thread *outbufev;
+       /** Connection event. */
+       struct thread *connectev;
+
+       /** Amount of bytes read. */
+       uint64_t in_bytes;
+       /** Amount of bytes read peak. */
+       uint64_t in_bytes_peak;
+       /** Amount of bytes written. */
+       uint64_t out_bytes;
+       /** Amount of bytes written peak. */
+       uint64_t out_bytes_peak;
+       /** Amount of output buffer full events (`bfd_dplane_enqueue` failed).
+        */
+       uint64_t out_fullev;
+
+       /** Amount of messages read (full messages). */
+       uint64_t in_msgs;
+       /** Amount of messages enqueued (maybe written). */
+       uint64_t out_msgs;
+
+       TAILQ_ENTRY(bfd_dplane_ctx) entry;
+};
+
+/**
+ * Callback type for `bfd_dplane_expect`. \see bfd_dplane_expect.
+ */
+typedef void (*bfd_dplane_expect_cb)(struct bfddp_message *msg, void *arg);
+
+static int bfd_dplane_client_connect(struct thread *t);
+static bool bfd_dplane_client_connecting(struct bfd_dplane_ctx *bdc);
+static void bfd_dplane_ctx_free(struct bfd_dplane_ctx *bdc);
+static int _bfd_dplane_add_session(struct bfd_dplane_ctx *bdc,
+                                  struct bfd_session *bs);
+
+/*
+ * BFD data plane helper functions.
+ */
+static const char *bfd_dplane_messagetype2str(enum bfddp_message_type bmt)
+{
+       switch (bmt) {
+       case ECHO_REQUEST:
+               return "ECHO_REQUEST";
+       case ECHO_REPLY:
+               return "ECHO_REPLY";
+       case DP_ADD_SESSION:
+               return "DP_ADD_SESSION";
+       case DP_DELETE_SESSION:
+               return "DP_DELETE_SESSION";
+       case BFD_STATE_CHANGE:
+               return "BFD_STATE_CHANGE";
+       case DP_REQUEST_SESSION_COUNTERS:
+               return "DP_REQUEST_SESSION_COUNTERS";
+       case BFD_SESSION_COUNTERS:
+               return "BFD_SESSION_COUNTERS";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+static void bfd_dplane_debug_message(const struct bfddp_message *msg)
+{
+       enum bfddp_message_type bmt;
+       char buf[256], addrs[256];
+       uint32_t flags;
+       int rv;
+
+       if (!bglobal.debug_dplane)
+               return;
+
+       bmt = ntohs(msg->header.type);
+       zlog_debug("dplane-packet: [version=%d length=%d type=%s (%d)]",
+                  msg->header.version, ntohs(msg->header.length),
+                  bfd_dplane_messagetype2str(bmt), bmt);
+
+       switch (bmt) {
+       case ECHO_REPLY:
+       case ECHO_REQUEST:
+               zlog_debug("  [dp_time=%" PRIu64 " bfdd_time=%" PRIu64 "]",
+                          (uint64_t)be64toh(msg->data.echo.dp_time),
+                          (uint64_t)be64toh(msg->data.echo.bfdd_time));
+               break;
+
+       case DP_ADD_SESSION:
+       case DP_DELETE_SESSION:
+               flags = ntohl(msg->data.session.flags);
+               if (flags & SESSION_IPV6)
+                       snprintfrr(addrs, sizeof(addrs), "src=%pI6 dst=%pI6",
+                                  &msg->data.session.src,
+                                  &msg->data.session.dst);
+               else
+                       snprintfrr(addrs, sizeof(addrs), "src=%pI4 dst=%pI4",
+                                  &msg->data.session.src,
+                                  &msg->data.session.dst);
+
+               buf[0] = 0;
+               if (flags & SESSION_CBIT)
+                       strlcat(buf, "cpi ", sizeof(buf));
+               if (flags & SESSION_ECHO)
+                       strlcat(buf, "echo ", sizeof(buf));
+               if (flags & SESSION_IPV6)
+                       strlcat(buf, "ipv6 ", sizeof(buf));
+               if (flags & SESSION_DEMAND)
+                       strlcat(buf, "demand ", sizeof(buf));
+               if (flags & SESSION_PASSIVE)
+                       strlcat(buf, "passive ", sizeof(buf));
+               if (flags & SESSION_MULTIHOP)
+                       strlcat(buf, "multihop ", sizeof(buf));
+               if (flags & SESSION_SHUTDOWN)
+                       strlcat(buf, "shutdown ", sizeof(buf));
+
+               /* Remove the last space to make things prettier. */
+               rv = (int)strlen(buf);
+               if (rv > 0)
+                       buf[rv - 1] = 0;
+
+               zlog_debug(
+                       "  [flags=0x%08x{%s} %s ttl=%d detect_mult=%d "
+                       "ifindex=%d ifname=%s]",
+                       flags, buf, addrs, msg->data.session.ttl,
+                       msg->data.session.detect_mult,
+                       ntohl(msg->data.session.ifindex),
+                       msg->data.session.ifname);
+               break;
+
+       case BFD_STATE_CHANGE:
+               buf[0] = 0;
+               flags = ntohl(msg->data.state.remote_flags);
+               if (flags & RBIT_CPI)
+                       strlcat(buf, "cbit ", sizeof(buf));
+               if (flags & RBIT_DEMAND)
+                       strlcat(buf, "demand ", sizeof(buf));
+               if (flags & RBIT_MP)
+                       strlcat(buf, "mp ", sizeof(buf));
+
+               /* Remove the last space to make things prettier. */
+               rv = (int)strlen(buf);
+               if (rv > 0)
+                       buf[rv - 1] = 0;
+
+               zlog_debug(
+                       "  [lid=%u rid=%u flags=0x%02x{%s} state=%s "
+                       "diagnostics=%s mult=%d tx=%u rx=%u erx=%u]",
+                       ntohl(msg->data.state.lid), ntohl(msg->data.state.rid),
+                       flags, buf, state_list[msg->data.state.state].str,
+                       diag2str(msg->data.state.diagnostics),
+                       msg->data.state.detection_multiplier,
+                       ntohl(msg->data.state.desired_tx),
+                       ntohl(msg->data.state.required_rx),
+                       ntohl(msg->data.state.required_echo_rx));
+               break;
+
+       case DP_REQUEST_SESSION_COUNTERS:
+               zlog_debug("  [lid=%u]", ntohl(msg->data.counters_req.lid));
+               break;
+
+       case BFD_SESSION_COUNTERS:
+               zlog_debug(
+                       "  [lid=%u "
+                       "control{in %" PRIu64 " bytes (%" PRIu64
+                       " packets), "
+                       "out %" PRIu64 " bytes (%" PRIu64
+                       " packets)} "
+                       "echo{in %" PRIu64 " bytes (%" PRIu64
+                       " packets), "
+                       "out %" PRIu64 " bytes (%" PRIu64 " packets)}]",
+                       ntohl(msg->data.session_counters.lid),
+                       (uint64_t)be64toh(
+                               msg->data.session_counters.control_input_bytes),
+                       (uint64_t)be64toh(msg->data.session_counters
+                                          .control_input_packets),
+                       (uint64_t)be64toh(msg->data.session_counters
+                                          .control_output_bytes),
+                       (uint64_t)be64toh(msg->data.session_counters
+                                          .control_output_packets),
+                       (uint64_t)be64toh(msg->data.session_counters.echo_input_bytes),
+                       (uint64_t)be64toh(
+                               msg->data.session_counters.echo_input_packets),
+                       (uint64_t)be64toh(
+                               msg->data.session_counters.echo_output_bytes),
+                       (uint64_t)be64toh(msg->data.session_counters
+                                          .echo_output_packets));
+               break;
+       }
+}
+
+/**
+ * Gets the next unused non zero identification.
+ *
+ * \param bdc the data plane context.
+ *
+ * \returns next usable id.
+ */
+static uint16_t bfd_dplane_next_id(struct bfd_dplane_ctx *bdc)
+{
+       bdc->last_id++;
+
+       /* Don't use reserved id `0`. */
+       if (bdc->last_id == 0)
+               bdc->last_id = 1;
+
+       return bdc->last_id;
+}
+
+static ssize_t bfd_dplane_flush(struct bfd_dplane_ctx *bdc)
+{
+       ssize_t total = 0;
+       int rv;
+
+       while (STREAM_READABLE(bdc->outbuf)) {
+               /* Flush buffer contents to socket. */
+               rv = stream_flush(bdc->outbuf, bdc->sock);
+               if (rv == -1) {
+                       /* Interruption: try again. */
+                       if (errno == EAGAIN || errno == EWOULDBLOCK
+                           || errno == EINTR)
+                               continue;
+
+                       zlog_warn("%s: socket failed: %s", __func__,
+                                 strerror(errno));
+                       bfd_dplane_ctx_free(bdc);
+                       return 0;
+               }
+               if (rv == 0) {
+                       if (bglobal.debug_dplane)
+                               zlog_info("%s: connection closed", __func__);
+
+                       bfd_dplane_ctx_free(bdc);
+                       return 0;
+               }
+
+               /* Account total written. */
+               total += rv;
+
+               /* Account output bytes. */
+               bdc->out_bytes += (uint64_t)rv;
+
+               /* Forward pointer. */
+               stream_forward_getp(bdc->outbuf, (size_t)rv);
+       }
+
+       /* Make more space for new data. */
+       stream_pulldown(bdc->outbuf);
+
+       /* Disable write ready events. */
+       THREAD_OFF(bdc->outbufev);
+
+       return total;
+}
+
+static int bfd_dplane_write(struct thread *t)
+{
+       struct bfd_dplane_ctx *bdc = THREAD_ARG(t);
+
+       /* Handle connection stage. */
+       if (bdc->connecting && bfd_dplane_client_connecting(bdc))
+               return 0;
+
+       bfd_dplane_flush(bdc);
+
+       return 0;
+}
+
+static void
+bfd_dplane_session_state_change(struct bfd_dplane_ctx *bdc,
+                               const struct bfddp_state_change *state)
+{
+       struct bfd_session *bs;
+       uint32_t flags;
+       int old_state;
+
+       /* Look up session. */
+       bs = bfd_id_lookup(ntohl(state->lid));
+       if (bs == NULL) {
+               if (bglobal.debug_dplane)
+                       zlog_debug("%s: failed to find session to update",
+                                  __func__);
+               return;
+       }
+
+       flags = ntohl(state->remote_flags);
+       old_state = bs->ses_state;
+
+       /* Update session state. */
+       bs->ses_state = state->state;
+       bs->remote_diag = state->diagnostics;
+       bs->discrs.remote_discr = ntohl(state->rid);
+       bs->remote_cbit = !!(flags & RBIT_CPI);
+       bs->remote_detect_mult = state->detection_multiplier;
+       bs->remote_timers.desired_min_tx = ntohl(state->desired_tx);
+       bs->remote_timers.required_min_rx = ntohl(state->required_rx);
+       bs->remote_timers.required_min_echo = ntohl(state->required_echo_rx);
+
+       /* Notify and update counters. */
+       control_notify(bs, bs->ses_state);
+
+       /* No state change. */
+       if (old_state == bs->ses_state)
+               return;
+
+       switch (bs->ses_state) {
+       case PTM_BFD_ADM_DOWN:
+       case PTM_BFD_DOWN:
+               /* Both states mean down. */
+               if (old_state == PTM_BFD_ADM_DOWN || old_state == PTM_BFD_DOWN)
+                       break;
+
+               monotime(&bs->downtime);
+               bs->stats.session_down++;
+               break;
+       case PTM_BFD_UP:
+               monotime(&bs->uptime);
+               bs->stats.session_up++;
+               break;
+       case PTM_BFD_INIT:
+               /* NOTHING */
+               break;
+
+       default:
+               zlog_warn("%s: unhandled new state %d", __func__,
+                         bs->ses_state);
+               break;
+       }
+
+       if (bglobal.debug_peer_event)
+               zlog_debug("state-change: [data plane: %s] %s -> %s",
+                          bs_to_string(bs), state_list[old_state].str,
+                          state_list[bs->ses_state].str);
+}
+
+/**
+ * Enqueue message in output buffer.
+ *
+ * \param[in,out] bdc data plane client context.
+ * \param[in] buf the message to buffer.
+ * \param[in] buflen the amount of bytes to buffer.
+ *
+ * \returns `-1` on failure (buffer full) or `0` on success.
+ */
+static int bfd_dplane_enqueue(struct bfd_dplane_ctx *bdc, const void *buf,
+                             size_t buflen)
+{
+       size_t rlen;
+
+       /* Handle not connected yet client. */
+       if (bdc->client && bdc->sock == -1)
+               return -1;
+
+       /* Not enough space. */
+       if (buflen > STREAM_WRITEABLE(bdc->outbuf)) {
+               bdc->out_fullev++;
+               return -1;
+       }
+
+       /* Show debug message if active. */
+       bfd_dplane_debug_message((struct bfddp_message *)buf);
+
+       /* Buffer the message. */
+       stream_write(bdc->outbuf, buf, buflen);
+
+       /* Account message as sent. */
+       bdc->out_msgs++;
+       /* Register peak buffered bytes. */
+       rlen = STREAM_READABLE(bdc->outbuf);
+       if (bdc->out_bytes_peak < rlen)
+               bdc->out_bytes_peak = rlen;
+
+       /* Schedule if it is not yet. */
+       if (bdc->outbufev == NULL)
+               thread_add_write(master, bfd_dplane_write, bdc, bdc->sock,
+                                &bdc->outbufev);
+
+       return 0;
+}
+
+static void bfd_dplane_echo_request_handle(struct bfd_dplane_ctx *bdc,
+                                          const struct bfddp_message *bm)
+{
+       struct bfddp_message msg = {};
+       uint16_t msglen = sizeof(msg.header) + sizeof(msg.data.echo);
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+
+       /* Prepare header. */
+       msg.header.version = BFD_DP_VERSION;
+       msg.header.type = htons(ECHO_REPLY);
+       msg.header.length = htons(msglen);
+
+       /* Prepare payload. */
+       msg.data.echo.dp_time = bm->data.echo.dp_time;
+       msg.data.echo.bfdd_time =
+               htobe64((uint64_t)((tv.tv_sec * 1000000) + tv.tv_usec));
+
+       /* Enqueue for output. */
+       bfd_dplane_enqueue(bdc, &msg, msglen);
+}
+
+static void bfd_dplane_handle_message(struct bfddp_message *msg, void *arg)
+{
+       enum bfddp_message_type bmt;
+       struct bfd_dplane_ctx *bdc = arg;
+
+       /* Call the appropriated handler. */
+       bmt = ntohs(msg->header.type);
+       switch (bmt) {
+       case ECHO_REQUEST:
+               bfd_dplane_echo_request_handle(bdc, msg);
+               break;
+       case BFD_STATE_CHANGE:
+               bfd_dplane_session_state_change(bdc, &msg->data.state);
+               break;
+       case ECHO_REPLY:
+               /* NOTHING: we don't do anything with this information. */
+               break;
+       case DP_ADD_SESSION:
+       case DP_DELETE_SESSION:
+       case DP_REQUEST_SESSION_COUNTERS:
+               /* NOTHING: we are not supposed to receive this. */
+               break;
+       case BFD_SESSION_COUNTERS:
+               /*
+                * NOTHING: caller of DP_REQUEST_SESSION_COUNTERS should
+                * handle this with `bfd_dplane_expect`.
+                */
+               break;
+
+       default:
+               zlog_debug("%s: unhandled message type %d", __func__, bmt);
+               break;
+       }
+}
+
+/**
+ * Reads the socket immediately to receive data plane answer to query.
+ *
+ * \param bdc the data plane context.
+ * \param id the message ID waiting response.
+ * \param cb the callback to call when ready.
+ * \param arg the callback argument.
+ *
+ * \return
+ * `-2` on unavailability (try again), `-1` on failure or `0` on success.
+ */
+static int bfd_dplane_expect(struct bfd_dplane_ctx *bdc, uint16_t id,
+                            bfd_dplane_expect_cb cb, void *arg)
+{
+       struct bfddp_message_header *bh;
+       size_t rlen = 0, reads = 0;
+       ssize_t rv;
+
+       /*
+        * Don't attempt to read if buffer is full, otherwise we'll get a
+        * bogus 'connection closed' signal (rv == 0).
+        */
+       if (bdc->inbuf->endp == bdc->inbuf->size)
+               goto skip_read;
+
+read_again:
+       /* Attempt to read message from client. */
+       rv = stream_read_try(bdc->inbuf, bdc->sock,
+                            STREAM_WRITEABLE(bdc->inbuf));
+       if (rv == 0) {
+               if (bglobal.debug_dplane)
+                       zlog_info("%s: socket closed", __func__);
+
+               bfd_dplane_ctx_free(bdc);
+               return -1;
+       }
+       if (rv == -1) {
+               zlog_warn("%s: socket failed: %s", __func__, strerror(errno));
+               bfd_dplane_ctx_free(bdc);
+               return -1;
+       }
+
+       /* We got interrupted, reschedule read. */
+       if (rv == -2)
+               return -2;
+
+       /* Account read bytes. */
+       bdc->in_bytes += (uint64_t)rv;
+       /* Register peak buffered bytes. */
+       rlen = STREAM_READABLE(bdc->inbuf);
+       if (bdc->in_bytes_peak < rlen)
+               bdc->in_bytes_peak = rlen;
+
+skip_read:
+       while (rlen > 0) {
+               bh = (struct bfddp_message_header *)stream_pnt(bdc->inbuf);
+               /* Not enough data read. */
+               if (ntohs(bh->length) > rlen)
+                       goto read_again;
+
+               /* Account full message read. */
+               bdc->in_msgs++;
+
+               /* Account this message as whole read for buffer reorganize. */
+               reads++;
+
+               /* Check for bad version. */
+               if (bh->version != BFD_DP_VERSION) {
+                       zlog_err("%s: bad data plane client version: %d",
+                                __func__, bh->version);
+                       return -1;
+               }
+
+               /* Show debug message if active. */
+               bfd_dplane_debug_message((struct bfddp_message *)bh);
+
+               /*
+                * Handle incoming message with callback if the ID matches,
+                * otherwise fallback to default handler.
+                */
+               if (id && ntohs(bh->id) == id)
+                       cb((struct bfddp_message *)bh, arg);
+               else
+                       bfd_dplane_handle_message((struct bfddp_message *)bh,
+                                                 bdc);
+
+               /* Advance current read pointer. */
+               stream_forward_getp(bdc->inbuf, ntohs(bh->length));
+
+               /* Reduce the buffer available bytes. */
+               rlen -= ntohs(bh->length);
+
+               /* Reorganize buffer to handle more bytes read. */
+               if (reads >= 3) {
+                       stream_pulldown(bdc->inbuf);
+                       reads = 0;
+               }
+
+               /* We found the message, return to caller. */
+               if (id && ntohs(bh->id) == id)
+                       break;
+       }
+
+       return 0;
+}
+
+static int bfd_dplane_read(struct thread *t)
+{
+       struct bfd_dplane_ctx *bdc = THREAD_ARG(t);
+       int rv;
+
+       rv = bfd_dplane_expect(bdc, 0, bfd_dplane_handle_message, NULL);
+       if (rv == -1)
+               return 0;
+
+       stream_pulldown(bdc->inbuf);
+       thread_add_read(master, bfd_dplane_read, bdc, bdc->sock, &bdc->inbufev);
+       return 0;
+}
+
+static void _bfd_session_register_dplane(struct hash_bucket *hb, void *arg)
+{
+       struct bfd_session *bs = hb->data;
+       struct bfd_dplane_ctx *bdc = arg;
+
+       if (bs->bdc != NULL)
+               return;
+
+       /* Disable software session. */
+       bfd_session_disable(bs);
+
+       /* Move session to data plane. */
+       _bfd_dplane_add_session(bdc, bs);
+}
+
+static struct bfd_dplane_ctx *bfd_dplane_ctx_new(int sock)
+{
+       struct bfd_dplane_ctx *bdc;
+
+       bdc = XCALLOC(MTYPE_BFDD_DPLANE_CTX, sizeof(*bdc));
+       if (bdc == NULL)
+               return NULL;
+
+       bdc->sock = sock;
+       bdc->inbuf = stream_new(BFD_DPLANE_CLIENT_BUF_SIZE);
+       bdc->outbuf = stream_new(BFD_DPLANE_CLIENT_BUF_SIZE);
+
+       /* If not socket ready, skip read and session registration. */
+       if (sock == -1)
+               return bdc;
+
+       thread_add_read(master, bfd_dplane_read, bdc, sock, &bdc->inbufev);
+
+       /* Register all unattached sessions. */
+       bfd_key_iterate(_bfd_session_register_dplane, bdc);
+
+       return bdc;
+}
+
+static void _bfd_session_unregister_dplane(struct hash_bucket *hb, void *arg)
+{
+       struct bfd_session *bs = hb->data;
+       struct bfd_dplane_ctx *bdc = arg;
+
+       if (bs->bdc != bdc)
+               return;
+
+       bs->bdc = NULL;
+
+       /* Fallback to software. */
+       bfd_session_enable(bs);
+}
+
+static void bfd_dplane_ctx_free(struct bfd_dplane_ctx *bdc)
+{
+       if (bglobal.debug_dplane)
+               zlog_debug("%s: terminating data plane client %d", __func__,
+                          bdc->sock);
+
+       /* Client mode has special treatment. */
+       if (bdc->client) {
+               /* Disable connection event if any. */
+               THREAD_OFF(bdc->connectev);
+
+               /* Normal treatment on shutdown. */
+               if (bglobal.bg_shutdown)
+                       goto free_resources;
+
+               /* Attempt reconnection. */
+               socket_close(&bdc->sock);
+               THREAD_OFF(bdc->inbufev);
+               THREAD_OFF(bdc->outbufev);
+               thread_add_timer(master, bfd_dplane_client_connect, bdc, 3,
+                                &bdc->connectev);
+               return;
+       }
+
+free_resources:
+       /* Remove from the list of attached data planes. */
+       TAILQ_REMOVE(&bglobal.bg_dplaneq, bdc, entry);
+
+       /* Detach all associated sessions. */
+       if (bglobal.bg_shutdown == false)
+               bfd_key_iterate(_bfd_session_unregister_dplane, bdc);
+
+       /* Free resources. */
+       socket_close(&bdc->sock);
+       stream_free(bdc->inbuf);
+       stream_free(bdc->outbuf);
+       THREAD_OFF(bdc->inbufev);
+       THREAD_OFF(bdc->outbufev);
+       XFREE(MTYPE_BFDD_DPLANE_CTX, bdc);
+}
+
+static void _bfd_dplane_session_fill(const struct bfd_session *bs,
+                                    struct bfddp_message *msg)
+{
+       uint16_t msglen = sizeof(msg->header) + sizeof(msg->data.session);
+
+       /* Message header. */
+       msg->header.version = BFD_DP_VERSION;
+       msg->header.length = ntohs(msglen);
+       msg->header.type = ntohs(DP_ADD_SESSION);
+
+       /* Message payload. */
+       msg->data.session.dst = bs->key.peer;
+       msg->data.session.src = bs->key.local;
+       msg->data.session.detect_mult = bs->detect_mult;
+
+       if (bs->ifp) {
+               msg->data.session.ifindex = htonl(bs->ifp->ifindex);
+               strlcpy(msg->data.session.ifname, bs->ifp->name,
+                       sizeof(msg->data.session.ifname));
+       }
+       if (bs->flags & BFD_SESS_FLAG_MH) {
+               msg->data.session.flags |= SESSION_MULTIHOP;
+               msg->data.session.ttl = bs->mh_ttl;
+       } else
+               msg->data.session.ttl = BFD_TTL_VAL;
+
+       if (bs->flags & BFD_SESS_FLAG_IPV6)
+               msg->data.session.flags |= SESSION_IPV6;
+       if (bs->flags & BFD_SESS_FLAG_ECHO)
+               msg->data.session.flags |= SESSION_ECHO;
+       if (bs->flags & BFD_SESS_FLAG_CBIT)
+               msg->data.session.flags |= SESSION_CBIT;
+       if (bs->flags & BFD_SESS_FLAG_PASSIVE)
+               msg->data.session.flags |= SESSION_PASSIVE;
+       if (bs->flags & BFD_SESS_FLAG_SHUTDOWN)
+               msg->data.session.flags |= SESSION_SHUTDOWN;
+
+       msg->data.session.flags = htonl(msg->data.session.flags);
+       msg->data.session.lid = htonl(bs->discrs.my_discr);
+       msg->data.session.min_tx = htonl(bs->timers.desired_min_tx);
+       msg->data.session.min_rx = htonl(bs->timers.required_min_rx);
+       msg->data.session.min_echo_rx = htonl(bs->timers.required_min_echo);
+}
+
+static int _bfd_dplane_add_session(struct bfd_dplane_ctx *bdc,
+                                  struct bfd_session *bs)
+{
+       int rv;
+
+       /* Associate session. */
+       bs->bdc = bdc;
+
+       /* Reset previous state. */
+       bs->remote_diag = 0;
+       bs->local_diag = 0;
+       bs->ses_state = PTM_BFD_DOWN;
+
+       /* Enqueue message to data plane client. */
+       rv = bfd_dplane_update_session(bs);
+       if (rv != 0)
+               bs->bdc = NULL;
+
+       return rv;
+}
+
+static void _bfd_dplane_update_session_counters(struct bfddp_message *msg,
+                                               void *arg)
+{
+       struct bfd_session *bs = arg;
+
+       bs->stats.rx_ctrl_pkt =
+               be64toh(msg->data.session_counters.control_input_packets);
+       bs->stats.tx_ctrl_pkt =
+               be64toh(msg->data.session_counters.control_output_packets);
+       bs->stats.rx_echo_pkt =
+               be64toh(msg->data.session_counters.echo_input_packets);
+       bs->stats.tx_echo_pkt =
+               be64toh(msg->data.session_counters.echo_output_bytes);
+}
+
+/**
+ * Send message to data plane requesting the session counters.
+ *
+ * \param bs the BFD session.
+ *
+ * \returns `0` on failure or the request id.
+ */
+static uint16_t bfd_dplane_request_counters(const struct bfd_session *bs)
+{
+       struct bfddp_message msg = {};
+       size_t msglen = sizeof(msg.header) + sizeof(msg.data.counters_req);
+
+       /* Fill header information. */
+       msg.header.version = BFD_DP_VERSION;
+       msg.header.length = htons(msglen);
+       msg.header.type = htons(DP_REQUEST_SESSION_COUNTERS);
+       msg.header.id = htons(bfd_dplane_next_id(bs->bdc));
+
+       /* Session to get counters. */
+       msg.data.counters_req.lid = htonl(bs->discrs.my_discr);
+
+       /* If enqueue failed, let caller know. */
+       if (bfd_dplane_enqueue(bs->bdc, &msg, msglen) == -1)
+               return 0;
+
+       /* Flush socket. */
+       bfd_dplane_flush(bs->bdc);
+
+       return ntohs(msg.header.id);
+}
+
+/*
+ * Data plane listening socket.
+ */
+static int bfd_dplane_accept(struct thread *t)
+{
+       struct bfd_global *bg = THREAD_ARG(t);
+       struct bfd_dplane_ctx *bdc;
+       int sock;
+
+       /* Accept new connection. */
+       sock = accept(bg->bg_dplane_sock, NULL, 0);
+       if (sock == -1) {
+               zlog_warn("%s: accept failed: %s", __func__, strerror(errno));
+               goto reschedule_and_return;
+       }
+
+       /* Create and handle new connection. */
+       bdc = bfd_dplane_ctx_new(sock);
+       TAILQ_INSERT_TAIL(&bglobal.bg_dplaneq, bdc, entry);
+
+       if (bglobal.debug_dplane)
+               zlog_debug("%s: new data plane client connected", __func__);
+
+reschedule_and_return:
+       thread_add_read(master, bfd_dplane_accept, bg, bg->bg_dplane_sock,
+                       &bglobal.bg_dplane_sockev);
+       return 0;
+}
+
+/*
+ * Data plane connecting socket.
+ */
+static void _bfd_dplane_client_bootstrap(struct bfd_dplane_ctx *bdc)
+{
+       bdc->connecting = false;
+
+       /* Clean up buffers. */
+       stream_reset(bdc->inbuf);
+       stream_reset(bdc->outbuf);
+
+       /* Ask for read notifications. */
+       thread_add_read(master, bfd_dplane_read, bdc, bdc->sock, &bdc->inbufev);
+
+       /* Remove all sessions then register again to send them all. */
+       bfd_key_iterate(_bfd_session_unregister_dplane, bdc);
+       bfd_key_iterate(_bfd_session_register_dplane, bdc);
+}
+
+static bool bfd_dplane_client_connecting(struct bfd_dplane_ctx *bdc)
+{
+       int rv;
+       socklen_t rvlen = sizeof(rv);
+
+       /* Make sure `errno` is reset, then test `getsockopt` success. */
+       errno = 0;
+       if (getsockopt(bdc->sock, SOL_SOCKET, SO_ERROR, &rv, &rvlen) == -1)
+               rv = -1;
+
+       /* Connection successful. */
+       if (rv == 0) {
+               if (bglobal.debug_dplane)
+                       zlog_debug("%s: connected to server: %d", __func__,
+                                  bdc->sock);
+
+               _bfd_dplane_client_bootstrap(bdc);
+               return false;
+       }
+
+       switch (rv) {
+       case EINTR:
+       case EAGAIN:
+       case EALREADY:
+       case EINPROGRESS:
+               /* non error, wait more. */
+               return true;
+
+       default:
+               zlog_warn("%s: connection failed: %s", __func__,
+                         strerror(errno));
+               bfd_dplane_ctx_free(bdc);
+               return true;
+       }
+}
+
+static int bfd_dplane_client_connect(struct thread *t)
+{
+       struct bfd_dplane_ctx *bdc = THREAD_ARG(t);
+       int rv, sock;
+       socklen_t rvlen = sizeof(rv);
+
+       /* Allocate new socket. */
+       sock = socket(bdc->addr.sa.sa_family, SOCK_STREAM, 0);
+       if (sock == -1) {
+               zlog_warn("%s: failed to initialize socket: %s", __func__,
+                         strerror(errno));
+               goto reschedule_connect;
+       }
+
+       /* Set non blocking socket. */
+       set_nonblocking(sock);
+
+       /* Set 'no delay' (disables nagle algorithm) for IPv4/IPv6. */
+       rv = 1;
+       if (bdc->addr.sa.sa_family != AF_UNIX
+           && setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &rv, rvlen) == -1)
+               zlog_warn("%s: TCP_NODELAY: %s", __func__, strerror(errno));
+
+       /* Attempt to connect. */
+       rv = connect(sock, &bdc->addr.sa, bdc->addrlen);
+       if (rv == -1 && (errno != EINPROGRESS && errno != EAGAIN)) {
+               zlog_warn("%s: data plane connection failed: %s", __func__,
+                         strerror(errno));
+               goto reschedule_connect;
+       }
+
+       bdc->sock = sock;
+       if (rv == -1) {
+               if (bglobal.debug_dplane)
+                       zlog_debug("%s: server connection in progress: %d",
+                                  __func__, sock);
+
+               /* If we are not connected yet, ask for write notifications. */
+               bdc->connecting = true;
+               thread_add_write(master, bfd_dplane_write, bdc, bdc->sock,
+                                &bdc->outbufev);
+       } else {
+               if (bglobal.debug_dplane)
+                       zlog_debug("%s: server connection: %d", __func__, sock);
+
+               /* Otherwise just start accepting data. */
+               _bfd_dplane_client_bootstrap(bdc);
+       }
+
+       return 0;
+
+reschedule_connect:
+       THREAD_OFF(bdc->inbufev);
+       THREAD_OFF(bdc->outbufev);
+       socket_close(&sock);
+       thread_add_timer(master, bfd_dplane_client_connect, bdc, 3,
+                        &bdc->connectev);
+       return 0;
+}
+
+static void bfd_dplane_client_init(const struct sockaddr *sa, socklen_t salen)
+{
+       struct bfd_dplane_ctx *bdc;
+
+       /* Allocate context and copy address for reconnection. */
+       bdc = bfd_dplane_ctx_new(-1);
+       if (salen <= sizeof(bdc->addr)) {
+               memcpy(&bdc->addr, sa, salen);
+               bdc->addrlen = sizeof(bdc->addr);
+       } else {
+               memcpy(&bdc->addr, sa, sizeof(bdc->addr));
+               bdc->addrlen = sizeof(bdc->addr);
+               zlog_warn("%s: server address truncated (from %d to %d)",
+                         __func__, salen, bdc->addrlen);
+       }
+
+       bdc->client = true;
+
+       thread_add_timer(master, bfd_dplane_client_connect, bdc, 0,
+                        &bdc->connectev);
+
+       /* Insert into data plane lists. */
+       TAILQ_INSERT_TAIL(&bglobal.bg_dplaneq, bdc, entry);
+}
+
+/**
+ * Termination phase of the distributed BFD infrastructure: free all allocated
+ * resources.
+ */
+static int bfd_dplane_finish_late(void)
+{
+       struct bfd_dplane_ctx *bdc;
+
+       if (bglobal.debug_dplane)
+               zlog_debug("%s: terminating distributed BFD", __func__);
+
+       /* Free all data plane client contexts. */
+       while ((bdc = TAILQ_FIRST(&bglobal.bg_dplaneq)) != NULL)
+               bfd_dplane_ctx_free(bdc);
+
+       /* Cancel accept thread and close socket. */
+       THREAD_OFF(bglobal.bg_dplane_sockev);
+       close(bglobal.bg_dplane_sock);
+
+       return 0;
+}
+
+/*
+ * Data plane exported functions.
+ */
+void bfd_dplane_init(const struct sockaddr *sa, socklen_t salen, bool client)
+{
+       int sock;
+
+       zlog_info("initializing distributed BFD");
+
+       /* Initialize queue header. */
+       TAILQ_INIT(&bglobal.bg_dplaneq);
+
+       /* Initialize listening socket. */
+       bglobal.bg_dplane_sock = -1;
+
+       /* Observe shutdown events. */
+       hook_register(frr_fini, bfd_dplane_finish_late);
+
+       /* Handle client mode. */
+       if (client) {
+               bfd_dplane_client_init(sa, salen);
+               return;
+       }
+
+       /*
+        * Data plane socket creation:
+        * - Set REUSEADDR option for taking over previously open socket.
+        * - Bind to address requested (maybe IPv4, IPv6, UNIX etc...).
+        * - Listen on that address for new connections.
+        * - Ask to be waken up when a new connection comes.
+        */
+       sock = socket(sa->sa_family, SOCK_STREAM, 0);
+       if (sock == -1) {
+               zlog_warn("%s: failed to initialize socket: %s", __func__,
+                         strerror(errno));
+               return;
+       }
+
+       if (sockopt_reuseaddr(sock) == -1) {
+               zlog_warn("%s: failed to set reuseaddr: %s", __func__,
+                         strerror(errno));
+               close(sock);
+               return;
+       }
+
+       /* Handle UNIX socket: delete previous socket if any. */
+       if (sa->sa_family == AF_UNIX)
+               unlink(((struct sockaddr_un *)sa)->sun_path);
+
+       if (bind(sock, sa, salen) == -1) {
+               zlog_warn("%s: failed to bind socket: %s", __func__,
+                         strerror(errno));
+               close(sock);
+               return;
+       }
+
+       if (listen(sock, SOMAXCONN) == -1) {
+               zlog_warn("%s: failed to put socket on listen: %s", __func__,
+                         strerror(errno));
+               close(sock);
+               return;
+       }
+
+       bglobal.bg_dplane_sock = sock;
+       thread_add_read(master, bfd_dplane_accept, &bglobal, sock,
+                       &bglobal.bg_dplane_sockev);
+}
+
+int bfd_dplane_add_session(struct bfd_session *bs)
+{
+       struct bfd_dplane_ctx *bdc;
+
+       /* Select a data plane client to install session. */
+       TAILQ_FOREACH (bdc, &bglobal.bg_dplaneq, entry) {
+               if (_bfd_dplane_add_session(bdc, bs) == 0)
+                       return 0;
+       }
+
+       return -1;
+}
+
+int bfd_dplane_update_session(const struct bfd_session *bs)
+{
+       struct bfddp_message msg = {};
+
+       if (bs->bdc == NULL)
+               return 0;
+
+       _bfd_dplane_session_fill(bs, &msg);
+
+       /* Enqueue message to data plane client. */
+       return bfd_dplane_enqueue(bs->bdc, &msg, ntohs(msg.header.length));
+}
+
+int bfd_dplane_delete_session(struct bfd_session *bs)
+{
+       struct bfddp_message msg = {};
+       int rv;
+
+       /* Not using data plane, just return success. */
+       if (bs->bdc == NULL)
+               return 0;
+
+       /* Fill most of the common fields. */
+       _bfd_dplane_session_fill(bs, &msg);
+
+       /* Change the message type. */
+       msg.header.type = ntohs(DP_DELETE_SESSION);
+
+       /* Enqueue message to data plane client. */
+       rv = bfd_dplane_enqueue(bs->bdc, &msg, ntohs(msg.header.length));
+
+       /* Remove association. */
+       bs->bdc = NULL;
+
+       return rv;
+}
+
+/*
+ * Data plane CLI.
+ */
+void bfd_dplane_show_counters(struct vty *vty)
+{
+       struct bfd_dplane_ctx *bdc;
+
+#define SHOW_COUNTER(label, counter, formatter)                                \
+       vty_out(vty, "%28s: %" formatter "\n", (label), (counter))
+
+       vty_out(vty, "%28s\n%28s\n", "Data plane", "==========");
+       TAILQ_FOREACH (bdc, &bglobal.bg_dplaneq, entry) {
+               SHOW_COUNTER("File descriptor", bdc->sock, "d");
+               SHOW_COUNTER("Input bytes", bdc->in_bytes, PRIu64);
+               SHOW_COUNTER("Input bytes peak", bdc->in_bytes_peak, PRIu64);
+               SHOW_COUNTER("Input messages", bdc->in_msgs, PRIu64);
+               SHOW_COUNTER("Input current usage", STREAM_READABLE(bdc->inbuf),
+                            "zu");
+               SHOW_COUNTER("Output bytes", bdc->out_bytes, PRIu64);
+               SHOW_COUNTER("Output bytes peak", bdc->out_bytes_peak, PRIu64);
+               SHOW_COUNTER("Output messages", bdc->out_msgs, PRIu64);
+               SHOW_COUNTER("Output full events", bdc->out_fullev, PRIu64);
+               SHOW_COUNTER("Output current usage",
+                            STREAM_READABLE(bdc->inbuf), "zu");
+               vty_out(vty, "\n");
+       }
+#undef SHOW_COUNTER
+}
+
+int bfd_dplane_update_session_counters(struct bfd_session *bs)
+{
+       uint16_t id;
+       int rv;
+
+       /* If session is not using data plane, then just return success. */
+       if (bs->bdc == NULL)
+               return 0;
+
+       /* Make the request. */
+       id = bfd_dplane_request_counters(bs);
+       if (id == 0) {
+               zlog_debug("%s: counters request failed", __func__);
+               return -1;
+       }
+
+       /* Handle interruptions. */
+       do {
+               rv = bfd_dplane_expect(bs->bdc, id,
+                                      _bfd_dplane_update_session_counters, bs);
+       } while (rv == -2);
+
+       return rv;
+}
index 90e2df2367a876ab8db79922726c1d8d6a07d37a..57fb81aa27a733163a16c846dd3917eb766720c1 100644 (file)
@@ -669,17 +669,24 @@ static void bfdd_sessions_enable_interface(struct interface *ifp)
        struct bfd_session *bs;
        struct vrf *vrf;
 
+       vrf = vrf_lookup_by_id(ifp->vrf_id);
+       if (!vrf)
+               return;
+
        TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
                bs = bso->bso_bs;
-               /* Interface name mismatch. */
-               if (strcmp(ifp->name, bs->key.ifname))
-                       continue;
-               vrf = vrf_lookup_by_id(ifp->vrf_id);
-               if (!vrf)
-                       continue;
+               /* check vrf name */
                if (bs->key.vrfname[0] &&
                    strcmp(vrf->name, bs->key.vrfname))
                        continue;
+
+               /* If Interface matches vrfname, then bypass iface check */
+               if (vrf_is_backend_netns() || strcmp(ifp->name, vrf->name)) {
+                       /* Interface name mismatch. */
+                       if (strcmp(ifp->name, bs->key.ifname))
+                               continue;
+               }
+
                /* Skip enabled sessions. */
                if (bs->sock != -1)
                        continue;
@@ -703,7 +710,7 @@ static void bfdd_sessions_disable_interface(struct interface *ifp)
                        continue;
 
                bfd_session_disable(bs);
-
+               bs->ifp = NULL;
        }
 }
 
@@ -752,13 +759,15 @@ void bfdd_sessions_disable_vrf(struct vrf *vrf)
                        continue;
 
                bfd_session_disable(bs);
+               bs->vrf = NULL;
        }
 }
 
 static int bfd_ifp_destroy(struct interface *ifp)
 {
        if (bglobal.debug_zebra)
-               zlog_debug("zclient: delete interface %s", ifp->name);
+               zlog_debug("zclient: delete interface %s (VRF %u)", ifp->name,
+                          ifp->vrf_id);
 
        bfdd_sessions_disable_interface(ifp);
 
@@ -811,10 +820,10 @@ static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS)
                return 0;
 
        if (bglobal.debug_zebra)
-               zlog_debug("zclient: %s local address %pFX",
+               zlog_debug("zclient: %s local address %pFX (VRF %u)",
                           cmd == ZEBRA_INTERFACE_ADDRESS_ADD ? "add"
                                                              : "delete",
-                          ifc->address);
+                          ifc->address, vrf_id);
 
        if (cmd == ZEBRA_INTERFACE_ADDRESS_ADD)
                bfdd_sessions_enable_address(ifc);
@@ -827,8 +836,8 @@ static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS)
 static int bfd_ifp_create(struct interface *ifp)
 {
        if (bglobal.debug_zebra)
-               zlog_debug("zclient: add interface %s", ifp->name);
-
+               zlog_debug("zclient: add interface %s (VRF %u)", ifp->name,
+                          ifp->vrf_id);
        bfdd_sessions_enable_interface(ifp);
 
        return 0;
index d0e3c1e8d2d60fe185e89255832f0faf0081a789..e572d4a3c0b2b862f922a8e97e431e3694427d68 100644 (file)
@@ -22,10 +22,18 @@ bfdd_libbfd_a_SOURCES = \
        bfdd/bfd_packet.c \
        bfdd/config.c \
        bfdd/control.c \
+       bfdd/dplane.c \
        bfdd/event.c \
        bfdd/ptm_adapter.c \
        # end
 
+# Install headers so it can be used by external data plane
+# implementations.
+bfdd_headersdir = $(pkgincludedir)/bfdd
+bfdd_headers_HEADERS = \
+       bfdd/bfddp_packet.h \
+       # end
+
 clippy_scan += \
        bfdd/bfdd_cli.c \
        bfdd/bfdd_vty.c \
index f2cf78efdec06d3e498b4ef340f65c81889e053b..745a0dffce2c1a9daf7868e7051ec04b315b4389 100644 (file)
@@ -83,6 +83,9 @@ struct bgp_adj_out {
 
        /* Advertisement information.  */
        struct bgp_advertise *adv;
+
+       /* Attribute hash */
+       uint32_t attr_hash;
 };
 
 RB_HEAD(bgp_adj_out_rb, bgp_adj_out);
index ce22e8404d41eb90bac32454ddc0c250a2ea3fc0..c25d0e269a7b42dc09299d90d080c024dfb2d7dd 100644 (file)
@@ -3395,7 +3395,8 @@ void bgp_attr_extcom_tunnel_type(struct attr *attr,
                                 bgp_encap_types *tunnel_type)
 {
        struct ecommunity *ecom;
-       int i;
+       uint32_t i;
+
        if (!attr)
                return;
 
@@ -4021,7 +4022,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
                        uint8_t *pnt;
                        int tbit;
                        int ecom_tr_size = 0;
-                       int i;
+                       uint32_t i;
 
                        for (i = 0; i < attr->ecommunity->size; i++) {
                                pnt = attr->ecommunity->val + (i * 8);
index 7cc9ecd79edfc4a03bccda858e9e1bb84693bd1a..1df646c34652622e6f1388e55dcb5c0fb9c704a2 100644 (file)
@@ -89,7 +89,7 @@ char *ecom_mac2str(char *ecom_mac)
 /* Fetch router-mac from extended community */
 bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac)
 {
-       int i = 0;
+       uint32_t i = 0;
        struct ecommunity *ecom;
 
        ecom = attr->ecommunity;
@@ -122,7 +122,7 @@ bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac)
 uint8_t bgp_attr_default_gw(struct attr *attr)
 {
        struct ecommunity *ecom;
-       int i;
+       uint32_t i;
 
        ecom = attr->ecommunity;
        if (!ecom || !ecom->size)
@@ -153,7 +153,7 @@ uint8_t bgp_attr_default_gw(struct attr *attr)
 uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg)
 {
        struct ecommunity *ecom;
-       int i;
+       uint32_t i;
        uint16_t df_pref = 0;
 
        *alg = EVPN_MH_DF_ALG_SERVICE_CARVING;
@@ -190,7 +190,7 @@ uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg)
 uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
 {
        struct ecommunity *ecom;
-       int i;
+       uint32_t i;
        uint8_t flags = 0;
 
        ecom = attr->ecommunity;
@@ -237,7 +237,7 @@ void bgp_attr_evpn_na_flag(struct attr *attr,
                uint8_t *router_flag, bool *proxy)
 {
        struct ecommunity *ecom;
-       int i;
+       uint32_t i;
        uint8_t val;
 
        ecom = attr->ecommunity;
index af88547ca94aa2bc5a63a67ffe8be0e5df795181..82e27884cf0d45e5c029f1dd50de2fa1c81e06b8 100644 (file)
@@ -1329,6 +1329,33 @@ static int bmp_stats(struct thread *thread)
        return 0;
 }
 
+/* read from the BMP socket to detect session termination */
+static int bmp_read(struct thread *t)
+{
+       struct bmp *bmp = THREAD_ARG(t);
+       char buf[1024];
+       ssize_t n;
+
+       bmp->t_read = NULL;
+
+       n = read(bmp->socket, buf, sizeof(buf));
+       if (n >= 1) {
+               zlog_info("bmp[%s]: unexpectedly received %zu bytes", bmp->remote, n);
+       } else if (n == 0) {
+               /* the TCP session was terminated by the far end */
+               bmp_wrerr(bmp, NULL, true);
+               return 0;
+       } else if (!(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) {
+               /* the TCP session experienced a fatal error, likely a timeout */
+               bmp_wrerr(bmp, NULL, false);
+               return -1;
+       }
+
+       thread_add_read(bm->master, bmp_read, bmp, bmp->socket, &bmp->t_read);
+
+       return 0;
+}
+
 static struct bmp *bmp_open(struct bmp_targets *bt, int bmp_sock)
 {
        union sockunion su, *sumem;
@@ -1349,9 +1376,11 @@ static struct bmp *bmp_open(struct bmp_targets *bt, int bmp_sock)
 
        set_nonblocking(bmp_sock);
        set_cloexec(bmp_sock);
-       shutdown(bmp_sock, SHUT_RD);
 
-       sockunion2hostprefix(&su, &p);
+       if (!sockunion2hostprefix(&su, &p)) {
+               close(bmp_sock);
+               return NULL;
+       }
 
        acl = NULL;
        switch (p.family) {
@@ -1400,6 +1429,7 @@ static struct bmp *bmp_open(struct bmp_targets *bt, int bmp_sock)
        bmp->state = BMP_PeerUp;
        bmp->pullwr = pullwr_new(bm->master, bmp_sock, bmp, bmp_wrfill,
                        bmp_wrerr);
+       thread_add_read(bm->master, bmp_read, bmp, bmp_sock, &bmp->t_read);
        bmp_send_initiation(bmp);
 
        return bmp;
@@ -1432,6 +1462,8 @@ static void bmp_close(struct bmp *bmp)
        struct bmp_queue_entry *bqe;
        struct bmp_mirrorq *bmq;
 
+       THREAD_OFF(bmp->t_read);
+
        if (bmp->active)
                bmp_active_disconnected(bmp->active);
 
index 247d758f8cd6b7232946b81c807c5817d3aa3d46..6ac6cf56ddcfa1bc259aa4caf1a830f68db98cad 100644 (file)
@@ -1110,11 +1110,14 @@ struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom,
 }
 
 /* Helper to check if every octet do not exceed UINT_MAX */
-static bool lcommunity_list_valid(const char *community)
+bool lcommunity_list_valid(const char *community, int style)
 {
        int octets;
        char **splits, **communities;
+       char *endptr;
        int num, num_communities;
+       regex_t *regres;
+       int invalid = 0;
 
        frrstr_split(community, " ", &communities, &num_communities);
 
@@ -1123,25 +1126,43 @@ static bool lcommunity_list_valid(const char *community)
                frrstr_split(communities[j], ":", &splits, &num);
 
                for (int i = 0; i < num; i++) {
-                       if (strtoul(splits[i], NULL, 10) > UINT_MAX)
-                               return false;
-
                        if (strlen(splits[i]) == 0)
-                               return false;
+                               /* There is no digit to check */
+                               invalid++;
+
+                       if (style == LARGE_COMMUNITY_LIST_STANDARD) {
+                               if (*splits[i] == '-')
+                                       /* Must not be negative */
+                                       invalid++;
+                               else if (strtoul(splits[i], &endptr, 10)
+                                        > UINT_MAX)
+                                       /* Larger than 4 octets */
+                                       invalid++;
+                               else if (*endptr)
+                                       /* Not all characters were digits */
+                                       invalid++;
+                       } else {
+                               regres = bgp_regcomp(communities[j]);
+                               if (!regres)
+                                       /* malformed regex */
+                                       invalid++;
+                               else
+                                       bgp_regex_free(regres);
+                       }
 
                        octets++;
                        XFREE(MTYPE_TMP, splits[i]);
                }
                XFREE(MTYPE_TMP, splits);
 
-               if (octets < 3)
-                       return false;
+               if (octets != 3)
+                       invalid++;
 
                XFREE(MTYPE_TMP, communities[j]);
        }
        XFREE(MTYPE_TMP, communities);
 
-       return true;
+       return (invalid > 0) ? false : true;
 }
 
 /* Set lcommunity-list.  */
@@ -1176,7 +1197,7 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
        }
 
        if (str) {
-               if (!lcommunity_list_valid(str))
+               if (!lcommunity_list_valid(str, style))
                        return COMMUNITY_LIST_ERR_MALFORMED_VAL;
 
                if (style == LARGE_COMMUNITY_LIST_STANDARD)
index f7d46525a0d2ebc26380d739d7e0846629095e9b..632e1730cc6c3739e21878253190c0322e0a23e6 100644 (file)
@@ -154,6 +154,7 @@ extern int extcommunity_list_unset(struct community_list_handler *ch,
 extern int lcommunity_list_set(struct community_list_handler *ch,
                               const char *name, const char *str,
                               const char *seq, int direct, int style);
+extern bool lcommunity_list_valid(const char *community, int style);
 extern int lcommunity_list_unset(struct community_list_handler *ch,
                                 const char *name, const char *str,
                                 const char *seq, int direct, int style);
index b6cc2b839f36afeb3bc69e36a8839c39652d24c0..f722a8dbc79d6e15a534c61a72a657be7ade49b3 100644 (file)
@@ -24,6 +24,7 @@
 #include "hash.h"
 #include "memory.h"
 #include "jhash.h"
+#include "frrstr.h"
 
 #include "bgpd/bgp_memory.h"
 #include "bgpd/bgp_community.h"
@@ -648,6 +649,31 @@ enum community_token {
        community_token_unknown
 };
 
+/* Helper to check if a given community is valid */
+static bool community_valid(const char *community)
+{
+       int octets = 0;
+       char **splits;
+       int num;
+       int invalid = 0;
+
+       frrstr_split(community, ":", &splits, &num);
+
+       for (int i = 0; i < num; i++) {
+               if (strtoul(splits[i], NULL, 10) > UINT16_MAX)
+                       invalid++;
+
+               if (strlen(splits[i]) == 0)
+                       invalid++;
+
+               octets++;
+               XFREE(MTYPE_TMP, splits[i]);
+       }
+       XFREE(MTYPE_TMP, splits);
+
+       return (octets < 2 || invalid) ? false : true;
+}
+
 /* Get next community token from string. */
 static const char *
 community_gettoken(const char *buf, enum community_token *token, uint32_t *val)
@@ -780,6 +806,11 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val)
                uint32_t community_low = 0;
                uint32_t community_high = 0;
 
+               if (!community_valid(p)) {
+                       *token = community_token_unknown;
+                       return NULL;
+               }
+
                while (isdigit((unsigned char)*p) || *p == ':') {
                        if (*p == ':') {
                                if (separator) {
@@ -810,11 +841,6 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val)
                        return NULL;
                }
 
-               if (community_low > UINT16_MAX) {
-                       *token = community_token_unknown;
-                       return NULL;
-               }
-
                *val = community_high + community_low;
                *token = community_token_val;
                return p;
index b5cd1b52b73c0152bd78e94b7ff11d533a2db4a1..b9ea26e862c86e017fb44a1751b2a9ed90e6b070 100644 (file)
@@ -19,8 +19,7 @@
  */
 
 #include "bgpd/bgp_conditional_adv.h"
-
-const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
+#include "bgpd/bgp_vty.h"
 
 static route_map_result_t
 bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table,
@@ -198,10 +197,6 @@ static int bgp_conditional_adv_timer(struct thread *t)
                        continue;
 
                FOREACH_AFI_SAFI (afi, safi) {
-                       if (strmatch(get_afi_safi_str(afi, safi, true),
-                                    "Unknown"))
-                               continue;
-
                        if (!peer->afc_nego[afi][safi])
                                continue;
 
index 94a27ead0e454ce6e296e66e1f3b51bf48bb0487..b740979b82a993f509d2af989b54749026341c58 100644 (file)
 #include "bgpd/bgp_route.h"
 #include "bgpd/bgp_attr.h"
 #include "bgpd/bgp_advertise.h"
+#include "bgpd/bgp_vty.h"
 
-const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
+static void bgp_reuselist_add(struct reuselist *list,
+                             struct bgp_damp_info *info)
+{
+       struct reuselist_node *new_node;
+
+       assert(info);
+       new_node = XCALLOC(MTYPE_BGP_DAMP_REUSELIST, sizeof(*new_node));
+       new_node->info = info;
+       SLIST_INSERT_HEAD(list, new_node, entry);
+}
+
+static void bgp_reuselist_del(struct reuselist *list,
+                             struct reuselist_node **node)
+{
+       if ((*node) == NULL)
+               return;
+       assert(list && node && *node);
+       SLIST_REMOVE(list, (*node), reuselist_node, entry);
+       XFREE(MTYPE_BGP_DAMP_REUSELIST, (*node));
+       *node = NULL;
+}
+
+static void bgp_reuselist_switch(struct reuselist *source,
+                                struct reuselist_node *node,
+                                struct reuselist *target)
+{
+       assert(source && target && node);
+       SLIST_REMOVE(source, node, reuselist_node, entry);
+       SLIST_INSERT_HEAD(target, node, entry);
+}
+
+static void bgp_reuselist_free(struct reuselist *list)
+{
+       struct reuselist_node *rn;
+
+       assert(list);
+       while ((rn = SLIST_FIRST(list)) != NULL)
+               bgp_reuselist_del(list, &rn);
+}
+
+static struct reuselist_node *bgp_reuselist_find(struct reuselist *list,
+                                                struct bgp_damp_info *info)
+{
+       struct reuselist_node *rn;
+
+       assert(list && info);
+       SLIST_FOREACH (rn, list, entry) {
+               if (rn->info == info)
+                       return rn;
+       }
+       return NULL;
+}
+
+static void bgp_damp_info_unclaim(struct bgp_damp_info *bdi)
+{
+       struct reuselist_node *node;
 
-/* Global variable to access damping configuration */
-static struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
+       assert(bdi && bdi->config);
+       if (bdi->index == BGP_DAMP_NO_REUSE_LIST_INDEX) {
+               node = bgp_reuselist_find(&bdi->config->no_reuse_list, bdi);
+               if (node)
+                       bgp_reuselist_del(&bdi->config->no_reuse_list, &node);
+       } else {
+               node = bgp_reuselist_find(&bdi->config->reuse_list[bdi->index],
+                                         bdi);
+               if (node)
+                       bgp_reuselist_del(&bdi->config->reuse_list[bdi->index],
+                                         &node);
+       }
+       bdi->config = NULL;
+}
+
+static void bgp_damp_info_claim(struct bgp_damp_info *bdi,
+                               struct bgp_damp_config *bdc)
+{
+       assert(bdc && bdi);
+       if (bdi->config == NULL) {
+               bdi->config = bdc;
+               return;
+       }
+       bgp_damp_info_unclaim(bdi);
+       bdi->config = bdc;
+       bdi->afi = bdc->afi;
+       bdi->safi = bdc->safi;
+}
 
-/* Utility macro to add and delete BGP dampening information to no
-   used list.  */
-#define BGP_DAMP_LIST_ADD(N, A) BGP_PATH_INFO_ADD(N, A, no_reuse_list)
-#define BGP_DAMP_LIST_DEL(N, A) BGP_PATH_INFO_DEL(N, A, no_reuse_list)
+struct bgp_damp_config *get_active_bdc_from_pi(struct bgp_path_info *pi,
+                                              afi_t afi, safi_t safi)
+{
+       if (!pi)
+               return NULL;
+       if (CHECK_FLAG(pi->peer->af_flags[afi][safi],
+                      PEER_FLAG_CONFIG_DAMPENING))
+               return &pi->peer->damp[afi][safi];
+       if (peer_group_active(pi->peer))
+               if (CHECK_FLAG(pi->peer->group->conf->af_flags[afi][safi],
+                              PEER_FLAG_CONFIG_DAMPENING))
+                       return &pi->peer->group->conf->damp[afi][safi];
+       if (CHECK_FLAG(pi->peer->bgp->af_flags[afi][safi],
+                      BGP_CONFIG_DAMPENING))
+               return &pi->peer->bgp->damp[afi][safi];
+       return NULL;
+}
 
 /* Calculate reuse list index by penalty value.  */
 static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc)
 {
        unsigned int i;
-       int index;
+       unsigned int index;
 
        /*
         * reuse_limit can't be zero, this is for Coverity
@@ -73,27 +168,45 @@ static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc)
 static void bgp_reuse_list_add(struct bgp_damp_info *bdi,
                               struct bgp_damp_config *bdc)
 {
-       int index;
-
-       index = bdi->index = bgp_reuse_index(bdi->penalty, bdc);
-
-       bdi->prev = NULL;
-       bdi->next = bdc->reuse_list[index];
-       if (bdc->reuse_list[index])
-               bdc->reuse_list[index]->prev = bdi;
-       bdc->reuse_list[index] = bdi;
+       bgp_damp_info_claim(bdi, bdc);
+       bdi->index = bgp_reuse_index(bdi->penalty, bdc);
+       bgp_reuselist_add(&bdc->reuse_list[bdi->index], bdi);
 }
 
 /* Delete BGP dampening information from reuse list.  */
 static void bgp_reuse_list_delete(struct bgp_damp_info *bdi,
                                  struct bgp_damp_config *bdc)
 {
-       if (bdi->next)
-               bdi->next->prev = bdi->prev;
-       if (bdi->prev)
-               bdi->prev->next = bdi->next;
-       else
-               bdc->reuse_list[bdi->index] = bdi->next;
+       struct reuselist *list;
+       struct reuselist_node *rn;
+
+       list = &bdc->reuse_list[bdi->index];
+       rn = bgp_reuselist_find(list, bdi);
+       bgp_damp_info_unclaim(bdi);
+       bgp_reuselist_del(list, &rn);
+}
+
+static void bgp_no_reuse_list_add(struct bgp_damp_info *bdi,
+                                 struct bgp_damp_config *bdc)
+{
+       bgp_damp_info_claim(bdi, bdc);
+       bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
+       bgp_reuselist_add(&bdc->no_reuse_list, bdi);
+}
+
+static void bgp_no_reuse_list_delete(struct bgp_damp_info *bdi,
+                                    struct bgp_damp_config *bdc)
+{
+       struct reuselist_node *rn;
+
+       assert(bdc && bdi);
+       if (bdi->config == NULL) {
+               bgp_damp_info_unclaim(bdi);
+               return;
+       }
+       bdi->config = NULL;
+       rn = bgp_reuselist_find(&bdc->no_reuse_list, bdi);
+       bgp_reuselist_del(&bdc->no_reuse_list, &rn);
 }
 
 /* Return decayed penalty value.  */
@@ -116,32 +229,34 @@ int bgp_damp_decay(time_t tdiff, int penalty, struct bgp_damp_config *bdc)
    is evaluated.  RFC2439 Section 4.8.7.  */
 static int bgp_reuse_timer(struct thread *t)
 {
+       struct bgp_damp_config *bdc = THREAD_ARG(t);
        struct bgp_damp_info *bdi;
-       struct bgp_damp_info *next;
+       struct reuselist plist;
+       struct reuselist_node *node;
+       struct bgp *bgp;
        time_t t_now, t_diff;
 
-       struct bgp_damp_config *bdc = THREAD_ARG(t);
-
-       bdc->t_reuse = NULL;
        thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
                         &bdc->t_reuse);
 
        t_now = bgp_clock();
 
-       /* 1.  save a pointer to the current zeroth queue head and zero the
-          list head entry.  */
-       bdi = bdc->reuse_list[bdc->reuse_offset];
-       bdc->reuse_list[bdc->reuse_offset] = NULL;
+       /* 1.  save a pointer to the current queue head and zero the list head
+        * list head entry. */
+       assert(bdc->reuse_offset < bdc->reuse_list_size);
+       plist = bdc->reuse_list[bdc->reuse_offset];
+       node = SLIST_FIRST(&plist);
+       SLIST_INIT(&bdc->reuse_list[bdc->reuse_offset]);
 
        /* 2.  set offset = modulo reuse-list-size ( offset + 1 ), thereby
           rotating the circular queue of list-heads.  */
        bdc->reuse_offset = (bdc->reuse_offset + 1) % bdc->reuse_list_size;
+       assert(bdc->reuse_offset < bdc->reuse_list_size);
 
        /* 3. if ( the saved list head pointer is non-empty ) */
-       for (; bdi; bdi = next) {
-               struct bgp *bgp = bdi->path->peer->bgp;
-
-               next = bdi->next;
+       while ((node = SLIST_FIRST(&plist)) != NULL) {
+               bdi = node->info;
+               bgp = bdi->path->peer->bgp;
 
                /* Set t-diff = t-now - t-updated.  */
                t_diff = t_now - bdi->t_updated;
@@ -170,16 +285,27 @@ static int bgp_reuse_timer(struct thread *t)
                                            bdi->safi);
                        }
 
-                       if (bdi->penalty <= bdc->reuse_limit / 2.0)
-                               bgp_damp_info_free(bdi, 1, bdc->afi, bdc->safi);
-                       else
-                               BGP_DAMP_LIST_ADD(bdc, bdi);
-               } else
+                       if (bdi->penalty <= bdc->reuse_limit / 2.0) {
+                               bgp_damp_info_free(&bdi, bdc, 1, bdi->afi,
+                                                  bdi->safi);
+                               bgp_reuselist_del(&plist, &node);
+                       } else {
+                               node->info->index =
+                                       BGP_DAMP_NO_REUSE_LIST_INDEX;
+                               bgp_reuselist_switch(&plist, node,
+                                                    &bdc->no_reuse_list);
+                       }
+               } else {
                        /* Re-insert into another list (See RFC2439 Section
                         * 4.8.6).  */
-                       bgp_reuse_list_add(bdi, bdc);
+                       bdi->index = bgp_reuse_index(bdi->penalty, bdc);
+                       bgp_reuselist_switch(&plist, node,
+                                            &bdc->reuse_list[bdi->index]);
+               }
        }
 
+       assert(SLIST_EMPTY(&plist));
+
        return 0;
 }
 
@@ -190,10 +316,13 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
        time_t t_now;
        struct bgp_damp_info *bdi = NULL;
        unsigned int last_penalty = 0;
-       struct bgp_damp_config *bdc = &damp[afi][safi];
+       struct bgp_damp_config *bdc;
 
-       t_now = bgp_clock();
+       bdc = get_active_bdc_from_pi(path, afi, safi);
+       if (!bdc)
+               return BGP_DAMP_USED;
 
+       t_now = bgp_clock();
        /* Processing Unreachable Messages.  */
        if (path->extra)
                bdi = path->extra->damp_info;
@@ -215,12 +344,13 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
                bdi->flap = 1;
                bdi->start_time = t_now;
                bdi->suppress_time = 0;
-               bdi->index = -1;
+               bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
                bdi->afi = afi;
                bdi->safi = safi;
                (bgp_path_info_extra_get(path))->damp_info = bdi;
-               BGP_DAMP_LIST_ADD(bdc, bdi);
+               bgp_no_reuse_list_add(bdi, bdc);
        } else {
+               bgp_damp_info_claim(bdi, bdc);
                last_penalty = bdi->penalty;
 
                /* 1. Set t-diff = t-now - t-updated.  */
@@ -246,7 +376,7 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
        /* Remove the route from a reuse list if it is on one.  */
        if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)) {
                /* If decay rate isn't equal to 0, reinsert brn. */
-               if (bdi->penalty != last_penalty && bdi->index >= 0) {
+               if (bdi->penalty != last_penalty) {
                        bgp_reuse_list_delete(bdi, bdc);
                        bgp_reuse_list_add(bdi, bdc);
                }
@@ -258,10 +388,9 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
        if (bdi->penalty >= bdc->suppress_value) {
                bgp_path_info_set_flag(dest, path, BGP_PATH_DAMPED);
                bdi->suppress_time = t_now;
-               BGP_DAMP_LIST_DEL(bdc, bdi);
+               bgp_no_reuse_list_delete(bdi, bdc);
                bgp_reuse_list_add(bdi, bdc);
        }
-
        return BGP_DAMP_USED;
 }
 
@@ -271,7 +400,10 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
        time_t t_now;
        struct bgp_damp_info *bdi;
        int status;
-       struct bgp_damp_config *bdc = &damp[afi][safi];
+       struct bgp_damp_config *bdc;
+
+       bdc = get_active_bdc_from_pi(path, afi, safi);
+       assert(bdc);
 
        if (!path->extra || !((bdi = path->extra->damp_info)))
                return BGP_DAMP_USED;
@@ -290,7 +422,7 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
                 && (bdi->penalty < bdc->reuse_limit)) {
                bgp_path_info_unset_flag(dest, path, BGP_PATH_DAMPED);
                bgp_reuse_list_delete(bdi, bdc);
-               BGP_DAMP_LIST_ADD(bdc, bdi);
+               bgp_no_reuse_list_add(bdi, bdc);
                bdi->suppress_time = 0;
                status = BGP_DAMP_USED;
        } else
@@ -298,36 +430,29 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
 
        if (bdi->penalty > bdc->reuse_limit / 2.0)
                bdi->t_updated = t_now;
-       else
-               bgp_damp_info_free(bdi, 0, afi, safi);
+       else {
+               bgp_damp_info_unclaim(bdi);
+               bgp_damp_info_free(&bdi, bdc, 0, afi, safi);
+       }
 
        return status;
 }
 
-void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw, afi_t afi,
-                       safi_t safi)
+void bgp_damp_info_free(struct bgp_damp_info **bdi, struct bgp_damp_config *bdc,
+                       int withdraw, afi_t afi, safi_t safi)
 {
-       struct bgp_path_info *path;
-       struct bgp_damp_config *bdc = &damp[afi][safi];
+       assert(bdc && bdi && *bdi);
 
-       if (!bdi)
+       if ((*bdi)->path == NULL) {
+               XFREE(MTYPE_BGP_DAMP_INFO, (*bdi));
                return;
+       }
 
-       path = bdi->path;
-       path->extra->damp_info = NULL;
-
-       if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED))
-               bgp_reuse_list_delete(bdi, bdc);
-       else
-               BGP_DAMP_LIST_DEL(bdc, bdi);
-
-       bgp_path_info_unset_flag(bdi->dest, path,
+       (*bdi)->path->extra->damp_info = NULL;
+       bgp_path_info_unset_flag((*bdi)->dest, (*bdi)->path,
                                 BGP_PATH_HISTORY | BGP_PATH_DAMPED);
-
-       if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
-               bgp_path_info_delete(bdi->dest, path);
-
-       XFREE(MTYPE_BGP_DAMP_INFO, bdi);
+       if ((*bdi)->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
+               bgp_path_info_delete((*bdi)->dest, (*bdi)->path);
 }
 
 static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup,
@@ -370,8 +495,7 @@ static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup,
 
        bdc->reuse_list =
                XCALLOC(MTYPE_BGP_DAMP_ARRAY,
-                       bdc->reuse_list_size * sizeof(struct bgp_reuse_node *));
-
+                       bdc->reuse_list_size * sizeof(struct reuselist));
        /* Reuse-array computations */
        bdc->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
                                   sizeof(int) * bdc->reuse_index_size);
@@ -398,7 +522,7 @@ static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup,
 int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
                    unsigned int reuse, unsigned int suppress, time_t max)
 {
-       struct bgp_damp_config *bdc = &damp[afi][safi];
+       struct bgp_damp_config *bdc = &bgp->damp[afi][safi];
 
        if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
                if (bdc->half_life == half && bdc->reuse_limit == reuse
@@ -410,6 +534,8 @@ int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
 
        SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
        bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
+       bdc->afi = afi;
+       bdc->safi = safi;
 
        /* Register reuse timer.  */
        thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
@@ -418,8 +544,30 @@ int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
        return 0;
 }
 
-static void bgp_damp_config_clean(struct bgp_damp_config *bdc)
+/* Clean all the bgp_damp_info stored in reuse_list and no_reuse_list. */
+void bgp_damp_info_clean(struct bgp_damp_config *bdc, afi_t afi, safi_t safi)
 {
+       struct bgp_damp_info *bdi;
+       struct reuselist_node *rn;
+       struct reuselist *list;
+       unsigned int i;
+
+       bdc->reuse_offset = 0;
+       for (i = 0; i < bdc->reuse_list_size; ++i) {
+               list = &bdc->reuse_list[i];
+               while ((rn = SLIST_FIRST(list)) != NULL) {
+                       bdi = rn->info;
+                       bgp_reuselist_del(list, &rn);
+                       bgp_damp_info_free(&bdi, bdc, 1, afi, safi);
+               }
+       }
+
+       while ((rn = SLIST_FIRST(&bdc->no_reuse_list)) != NULL) {
+               bdi = rn->info;
+               bgp_reuselist_del(&bdc->no_reuse_list, &rn);
+               bgp_damp_info_free(&bdi, bdc, 1, afi, safi);
+       }
+
        /* Free decay array */
        XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->decay_array);
        bdc->decay_array_size = 0;
@@ -429,96 +577,81 @@ static void bgp_damp_config_clean(struct bgp_damp_config *bdc)
        bdc->reuse_index_size = 0;
 
        /* Free reuse list array. */
+       for (i = 0; i < bdc->reuse_list_size; ++i)
+               bgp_reuselist_free(&bdc->reuse_list[i]);
+
        XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_list);
        bdc->reuse_list_size = 0;
-}
-
-/* Clean all the bgp_damp_info stored in reuse_list. */
-void bgp_damp_info_clean(afi_t afi, safi_t safi)
-{
-       unsigned int i;
-       struct bgp_damp_info *bdi, *next;
-       struct bgp_damp_config *bdc = &damp[afi][safi];
-
-       bdc->reuse_offset = 0;
-
-       for (i = 0; i < bdc->reuse_list_size; i++) {
-               if (!bdc->reuse_list[i])
-                       continue;
-
-               for (bdi = bdc->reuse_list[i]; bdi; bdi = next) {
-                       next = bdi->next;
-                       bgp_damp_info_free(bdi, 1, afi, safi);
-               }
-               bdc->reuse_list[i] = NULL;
-       }
 
-       for (bdi = bdc->no_reuse_list; bdi; bdi = next) {
-               next = bdi->next;
-               bgp_damp_info_free(bdi, 1, afi, safi);
-       }
-       bdc->no_reuse_list = NULL;
+       THREAD_OFF(bdc->t_reuse);
 }
 
+/* Disable route flap dampening for a bgp instance.
+ *
+ * Please note that this function also gets used to free memory when deleting a
+ * bgp instance.
+ */
 int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi)
 {
-       struct bgp_damp_config *bdc = &damp[afi][safi];
+       struct bgp_damp_config *bdc;
+
+       bdc = &bgp->damp[afi][safi];
+       if (!bdc)
+               return 0;
+
        /* If it wasn't enabled, there's nothing to do. */
        if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
                return 0;
 
        /* Cancel reuse event. */
-       thread_cancel(&(bdc->t_reuse));
+       thread_cancel(&bdc->t_reuse);
 
        /* Clean BGP dampening information.  */
-       bgp_damp_info_clean(afi, safi);
-
-       /* Clear configuration */
-       bgp_damp_config_clean(bdc);
+       bgp_damp_info_clean(bdc, afi, safi);
 
        UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
+
        return 0;
 }
 
-void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi)
+void bgp_config_write_damp(struct vty *vty, struct bgp *bgp, afi_t afi,
+                          safi_t safi)
 {
-       if (damp[afi][safi].half_life == DEFAULT_HALF_LIFE * 60
-           && damp[afi][safi].reuse_limit == DEFAULT_REUSE
-           && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS
-           && damp[afi][safi].max_suppress_time
-                      == damp[afi][safi].half_life * 4)
+       struct bgp_damp_config *bdc;
+
+       bdc = &bgp->damp[afi][safi];
+       if (bdc->half_life == DEFAULT_HALF_LIFE * 60
+           && bdc->reuse_limit == DEFAULT_REUSE
+           && bdc->suppress_value == DEFAULT_SUPPRESS
+           && bdc->max_suppress_time == bdc->half_life * 4)
                vty_out(vty, "  bgp dampening\n");
-       else if (damp[afi][safi].half_life != DEFAULT_HALF_LIFE * 60
-                && damp[afi][safi].reuse_limit == DEFAULT_REUSE
-                && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS
-                && damp[afi][safi].max_suppress_time
-                           == damp[afi][safi].half_life * 4)
-               vty_out(vty, "  bgp dampening %lld\n",
-                       damp[afi][safi].half_life / 60LL);
+       else if (bdc->half_life != DEFAULT_HALF_LIFE * 60
+                && bdc->reuse_limit == DEFAULT_REUSE
+                && bdc->suppress_value == DEFAULT_SUPPRESS
+                && bdc->max_suppress_time == bdc->half_life * 4)
+               vty_out(vty, "  bgp dampening %lld\n", bdc->half_life / 60LL);
        else
                vty_out(vty, "  bgp dampening %lld %d %d %lld\n",
-                       damp[afi][safi].half_life / 60LL,
-                       damp[afi][safi].reuse_limit,
-                       damp[afi][safi].suppress_value,
-                       damp[afi][safi].max_suppress_time / 60LL);
+                       bdc->half_life / 60LL, bdc->reuse_limit,
+                       bdc->suppress_value, bdc->max_suppress_time / 60LL);
 }
 
-static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
-                                     size_t len, afi_t afi, safi_t safi,
-                                     bool use_json, json_object *json)
+static const char *bgp_get_reuse_time(struct bgp_damp_config *bdc,
+                                     unsigned int penalty, char *buf,
+                                     size_t len, bool use_json,
+                                     json_object *json)
 {
        time_t reuse_time = 0;
        struct tm tm;
        int time_store = 0;
 
-       if (penalty > damp[afi][safi].reuse_limit) {
+       if (penalty > bdc->reuse_limit) {
                reuse_time = (int)(DELTA_T
-                                  * ((log((double)damp[afi][safi].reuse_limit
-                                          / penalty))
-                                     / (log(damp[afi][safi].decay_array[1]))));
+                                  * ((log((double)bdc->reuse_limit / penalty))
+                                     / (log(bdc->decay_array[1]))));
 
-               if (reuse_time > damp[afi][safi].max_suppress_time)
-                       reuse_time = damp[afi][safi].max_suppress_time;
+               if (reuse_time > bdc->max_suppress_time)
+                       reuse_time = bdc->max_suppress_time;
 
                gmtime_r(&reuse_time, &tm);
        } else
@@ -570,14 +703,15 @@ static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
        return buf;
 }
 
-void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
-                      safi_t safi, json_object *json_path)
+void bgp_damp_info_vty(struct vty *vty, struct bgp *bgp,
+                      struct bgp_path_info *path, afi_t afi, safi_t safi,
+                      json_object *json_path)
 {
        struct bgp_damp_info *bdi;
        time_t t_now, t_diff;
        char timebuf[BGP_UPTIME_LEN];
        int penalty;
-       struct bgp_damp_config *bdc = &damp[afi][safi];
+       struct bgp_damp_config *bdc = &bgp->damp[afi][safi];
 
        if (!path->extra)
                return;
@@ -603,8 +737,8 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
 
                if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
                    && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
-                       bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN,
-                                          afi, safi, 1, json_path);
+                       bgp_get_reuse_time(bdc, penalty, timebuf,
+                                          BGP_UPTIME_LEN, 1, json_path);
        } else {
                vty_out(vty,
                        "      Dampinfo: penalty %d, flapped %d times in %s",
@@ -615,14 +749,15 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
                if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
                    && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
                        vty_out(vty, ", reuse in %s",
-                               bgp_get_reuse_time(penalty, timebuf,
-                                                  BGP_UPTIME_LEN, afi, safi, 0,
+                               bgp_get_reuse_time(bdc, penalty, timebuf,
+                                                  BGP_UPTIME_LEN, 0,
                                                   json_path));
 
                vty_out(vty, "\n");
        }
 }
 
+
 const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
                                    char *timebuf, size_t len, afi_t afi,
                                    safi_t safi, bool use_json,
@@ -631,7 +766,11 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
        struct bgp_damp_info *bdi;
        time_t t_now, t_diff;
        int penalty;
-       struct bgp_damp_config *bdc = &damp[afi][safi];
+       struct bgp_damp_config *bdc;
+
+       bdc = get_active_bdc_from_pi(path, afi, safi);
+       if (!bdc)
+               return NULL;
 
        if (!path->extra)
                return NULL;
@@ -649,24 +788,23 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
        t_diff = t_now - bdi->t_updated;
        penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
 
-       return bgp_get_reuse_time(penalty, timebuf, len, afi, safi, use_json,
-                                 json);
+       return bgp_get_reuse_time(bdc, penalty, timebuf, len, use_json, json);
 }
 
+
 static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty,
                                          afi_t afi, safi_t safi)
 {
+       struct bgp_damp_config *bdc;
        if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
+               bdc = &bgp->damp[afi][safi];
                vty_out(vty, "Half-life time: %lld min\n",
-                       (long long)damp[afi][safi].half_life / 60);
-               vty_out(vty, "Reuse penalty: %d\n",
-                       damp[afi][safi].reuse_limit);
-               vty_out(vty, "Suppress penalty: %d\n",
-                       damp[afi][safi].suppress_value);
+                       (long long)bdc->half_life / 60);
+               vty_out(vty, "Reuse penalty: %d\n", bdc->reuse_limit);
+               vty_out(vty, "Suppress penalty: %d\n", bdc->suppress_value);
                vty_out(vty, "Max suppress time: %lld min\n",
-                       (long long)damp[afi][safi].max_suppress_time / 60);
-               vty_out(vty, "Max suppress penalty: %u\n",
-                       damp[afi][safi].ceiling);
+                       (long long)bdc->max_suppress_time / 60);
+               vty_out(vty, "Max suppress penalty: %u\n", bdc->ceiling);
                vty_out(vty, "\n");
        } else
                vty_out(vty, "dampening not enabled for %s\n",
@@ -679,8 +817,8 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
                                  uint8_t show_flags)
 {
        struct bgp *bgp;
-       bgp = bgp_get_default();
 
+       bgp = bgp_get_default();
        if (bgp == NULL) {
                vty_out(vty, "No BGP process is configured\n");
                return CMD_WARNING;
@@ -719,3 +857,132 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
        }
        return CMD_SUCCESS;
 }
+
+void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi,
+                         time_t half, unsigned int reuse,
+                         unsigned int suppress, time_t max)
+{
+       struct bgp_damp_config *bdc;
+
+       if (!peer)
+               return;
+       bdc = &peer->damp[afi][safi];
+       if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING)) {
+               if (bdc->half_life == half && bdc->reuse_limit == reuse
+                   && bdc->suppress_value == suppress
+                   && bdc->max_suppress_time == max)
+                       return;
+               bgp_peer_damp_disable(peer, afi, safi);
+       }
+       SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING);
+       bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
+       bdc->afi = afi;
+       bdc->safi = safi;
+       thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
+                        &bdc->t_reuse);
+}
+
+/* Disable route flap dampening for a peer.
+ *
+ * Please note that this function also gets used to free memory when deleting a
+ * peer or peer group.
+ */
+void bgp_peer_damp_disable(struct peer *peer, afi_t afi, safi_t safi)
+{
+       struct bgp_damp_config *bdc;
+
+       if (!peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING))
+               return;
+       bdc = &peer->damp[afi][safi];
+       if (!bdc)
+               return;
+       bgp_damp_info_clean(bdc, afi, safi);
+       UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING);
+}
+
+void bgp_config_write_peer_damp(struct vty *vty, struct peer *peer, afi_t afi,
+                               safi_t safi)
+{
+       struct bgp_damp_config *bdc;
+
+       bdc = &peer->damp[afi][safi];
+       if (bdc->half_life == DEFAULT_HALF_LIFE * 60
+           && bdc->reuse_limit == DEFAULT_REUSE
+           && bdc->suppress_value == DEFAULT_SUPPRESS
+           && bdc->max_suppress_time == bdc->half_life * 4)
+               vty_out(vty, "  neighbor %s dampening\n", peer->host);
+       else if (bdc->half_life != DEFAULT_HALF_LIFE * 60
+                && bdc->reuse_limit == DEFAULT_REUSE
+                && bdc->suppress_value == DEFAULT_SUPPRESS
+                && bdc->max_suppress_time == bdc->half_life * 4)
+               vty_out(vty, "  neighbor %s dampening %lld\n", peer->host,
+                       bdc->half_life / 60LL);
+       else
+               vty_out(vty, "  neighbor %s dampening %lld %d %d %lld\n",
+                       peer->host, bdc->half_life / 60LL, bdc->reuse_limit,
+                       bdc->suppress_value, bdc->max_suppress_time / 60LL);
+}
+
+static void bgp_print_peer_dampening_parameters(struct vty *vty,
+                                               struct peer *peer, afi_t afi,
+                                               safi_t safi, bool use_json,
+                                               json_object *json)
+{
+       struct bgp_damp_config *bdc;
+
+       if (!peer)
+               return;
+       if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING)) {
+               bdc = &peer->damp[afi][safi];
+               if (!bdc)
+                       return;
+               if (use_json) {
+                       json_object_int_add(json, "halfLifeSecs",
+                                           bdc->half_life);
+                       json_object_int_add(json, "reusePenalty",
+                                           bdc->reuse_limit);
+                       json_object_int_add(json, "suppressPenalty",
+                                           bdc->suppress_value);
+                       json_object_int_add(json, "maxSuppressTimeSecs",
+                                           bdc->max_suppress_time);
+                       json_object_int_add(json, "maxSuppressPenalty",
+                                           bdc->ceiling);
+               } else {
+                       vty_out(vty, "Half-life time: %lld min\n",
+                               (long long)bdc->half_life / 60);
+                       vty_out(vty, "Reuse penalty: %d\n", bdc->reuse_limit);
+                       vty_out(vty, "Suppress penalty: %d\n",
+                               bdc->suppress_value);
+                       vty_out(vty, "Max suppress time: %lld min\n",
+                               (long long)bdc->max_suppress_time / 60);
+                       vty_out(vty, "Max suppress penalty: %u\n",
+                               bdc->ceiling);
+                       vty_out(vty, "\n");
+               }
+       } else if (!use_json)
+               vty_out(vty, "neighbor dampening not enabled for %s\n",
+                       get_afi_safi_str(afi, safi, false));
+}
+
+void bgp_show_peer_dampening_parameters(struct vty *vty, struct peer *peer,
+                                       afi_t afi, safi_t safi, bool use_json)
+{
+       json_object *json;
+
+       if (use_json) {
+               json = json_object_new_object();
+               json_object_string_add(json, "addressFamily",
+                                      get_afi_safi_str(afi, safi, false));
+               bgp_print_peer_dampening_parameters(vty, peer, afi, safi, true,
+                                                   json);
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       } else {
+               vty_out(vty, "\nFor address family: %s\n",
+                       get_afi_safi_str(afi, safi, false));
+               bgp_print_peer_dampening_parameters(vty, peer, afi, safi, false,
+                                                   NULL);
+       }
+}
index 604706300bc89ebb4165279e4c00404c0ae24d78..521f59b296553901fafc1870a433f1bbf9075022 100644 (file)
 
 /* Structure maintained on a per-route basis. */
 struct bgp_damp_info {
-       /* Doubly linked list.  This information must be linked to
-          reuse_list or no_reuse_list.  */
-       struct bgp_damp_info *next;
-       struct bgp_damp_info *prev;
-
        /* Figure-of-merit.  */
        unsigned int penalty;
 
@@ -45,6 +40,9 @@ struct bgp_damp_info {
        /* Time of route start to be suppressed.  */
        time_t suppress_time;
 
+       /* Back reference to associated dampening configuration. */
+       struct bgp_damp_config *config;
+
        /* Back reference to bgp_path_info. */
        struct bgp_path_info *path;
 
@@ -53,6 +51,8 @@ struct bgp_damp_info {
 
        /* Current index in the reuse_list. */
        int index;
+#define BGP_DAMP_NO_REUSE_LIST_INDEX                                           \
+       (-1) /* index for elements on no_reuse_list */
 
        /* Last time message type. */
        uint8_t lastrecord;
@@ -63,6 +63,13 @@ struct bgp_damp_info {
        safi_t safi;
 };
 
+struct reuselist_node {
+       SLIST_ENTRY(reuselist_node) entry;
+       struct bgp_damp_info *info;
+};
+
+SLIST_HEAD(reuselist, reuselist_node);
+
 /* Specified parameter set configuration. */
 struct bgp_damp_config {
        /* Value over which routes suppressed.  */
@@ -100,11 +107,11 @@ struct bgp_damp_config {
        int *reuse_index;
 
        /* Reuse list array per-set based. */
-       struct bgp_damp_info **reuse_list;
-       int reuse_offset;
+       struct reuselist *reuse_list;
+       unsigned int reuse_offset;
 
        /* All dampening information which is not on reuse list.  */
-       struct bgp_damp_info *no_reuse_list;
+       struct reuselist no_reuse_list;
 
        /* Reuse timer thread per-set base. */
        struct thread *t_reuse;
@@ -132,6 +139,8 @@ struct bgp_damp_config {
 #define REUSE_LIST_SIZE          256
 #define REUSE_ARRAY_SIZE        1024
 
+extern struct bgp_damp_config *get_active_bdc_from_pi(struct bgp_path_info *pi,
+                                                     afi_t afi, safi_t safi);
 extern int bgp_damp_enable(struct bgp *, afi_t, safi_t, time_t, unsigned int,
                           unsigned int, time_t);
 extern int bgp_damp_disable(struct bgp *, afi_t, safi_t);
@@ -139,13 +148,18 @@ extern int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
                             afi_t afi, safi_t safi, int attr_change);
 extern int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
                           afi_t afi, safi_t saff);
-extern void bgp_damp_info_free(struct bgp_damp_info *path, int withdraw,
+extern void bgp_damp_info_free(struct bgp_damp_info **path,
+                              struct bgp_damp_config *bdc, int withdraw,
                               afi_t afi, safi_t safi);
-extern void bgp_damp_info_clean(afi_t afi, safi_t safi);
+extern void bgp_damp_info_clean(struct bgp_damp_config *bdc, afi_t afi,
+                               safi_t safi);
+extern void bgp_damp_config_clean(struct bgp_damp_config *bdc);
 extern int bgp_damp_decay(time_t, int, struct bgp_damp_config *damp);
-extern void bgp_config_write_damp(struct vty *, afi_t afi, safi_t safi);
-extern void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path,
-                             afi_t afi, safi_t safi, json_object *json_path);
+extern void bgp_config_write_damp(struct vty *vty, struct bgp *bgp, afi_t afi,
+                                 safi_t safi);
+extern void bgp_damp_info_vty(struct vty *vty, struct bgp *bgp,
+                             struct bgp_path_info *path, afi_t afi,
+                             safi_t safi, json_object *json_path);
 extern const char *bgp_damp_reuse_time_vty(struct vty *vty,
                                           struct bgp_path_info *path,
                                           char *timebuf, size_t len, afi_t afi,
@@ -153,5 +167,14 @@ extern const char *bgp_damp_reuse_time_vty(struct vty *vty,
                                           json_object *json);
 extern int bgp_show_dampening_parameters(struct vty *vty, afi_t, safi_t,
                                         uint8_t);
+extern void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi,
+                                time_t half, unsigned int reuse,
+                                unsigned int suppress, time_t max);
+extern void bgp_peer_damp_disable(struct peer *peer, afi_t afi, safi_t safi);
+extern void bgp_config_write_peer_damp(struct vty *vty, struct peer *peer,
+                                      afi_t afi, safi_t safi);
+extern void bgp_show_peer_dampening_parameters(struct vty *vty,
+                                              struct peer *peer, afi_t afi,
+                                              safi_t safi, bool use_json);
 
 #endif /* _QUAGGA_BGP_DAMP_H */
index 2c076fb80b2e6f863f8bf3fc95b11d8510ca265d..3afa6eaf09ee7a6bad0174bb243baf614531d579 100644 (file)
@@ -38,6 +38,7 @@
 #include "bgpd/bgp_attr.h"
 #include "bgpd/bgp_debug.h"
 #include "bgpd/bgp_community.h"
+#include "bgpd/bgp_lcommunity.h"
 #include "bgpd/bgp_updgrp.h"
 #include "bgpd/bgp_mplsvpn.h"
 #include "bgpd/bgp_ecommunity.h"
@@ -118,7 +119,7 @@ static const struct message bgp_notify_msg[] = {
        {BGP_NOTIFY_HOLD_ERR, "Hold Timer Expired"},
        {BGP_NOTIFY_FSM_ERR, "Neighbor Events Error"},
        {BGP_NOTIFY_CEASE, "Cease"},
-       {BGP_NOTIFY_CAPABILITY_ERR, "CAPABILITY Message Error"},
+       {BGP_NOTIFY_ROUTE_REFRESH_ERR, "ROUTE-REFRESH Message Error"},
        {0}};
 
 static const struct message bgp_notify_head_msg[] = {
@@ -166,11 +167,9 @@ static const struct message bgp_notify_cease_msg[] = {
        {BGP_NOTIFY_CEASE_OUT_OF_RESOURCE, "/Out of Resource"},
        {0}};
 
-static const struct message bgp_notify_capability_msg[] = {
+static const struct message bgp_notify_route_refresh_msg[] = {
        {BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"},
-       {BGP_NOTIFY_CAPABILITY_INVALID_ACTION, "/Invalid Action Value"},
-       {BGP_NOTIFY_CAPABILITY_INVALID_LENGTH, "/Invalid Capability Length"},
-       {BGP_NOTIFY_CAPABILITY_MALFORMED_CODE, "/Malformed Capability Value"},
+       {BGP_NOTIFY_ROUTE_REFRESH_INVALID_MSG_LEN, "/Invalid Message Length"},
        {0}};
 
 static const struct message bgp_notify_fsm_msg[] = {
@@ -411,6 +410,11 @@ bool bgp_dump_attr(struct attr *attr, char *buf, size_t size)
                         ", community %s",
                         community_str(attr->community, false));
 
+       if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)))
+               snprintf(buf + strlen(buf), size - strlen(buf),
+                        ", large-community %s",
+                        lcommunity_str(attr->lcommunity, false));
+
        if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
                snprintf(buf + strlen(buf), size - strlen(buf),
                         ", extcommunity %s", ecommunity_str(attr->ecommunity));
@@ -487,8 +491,8 @@ const char *bgp_notify_subcode_str(char code, char subcode)
        case BGP_NOTIFY_CEASE:
                return lookup_msg(bgp_notify_cease_msg, subcode,
                                  "Unrecognized Error Subcode");
-       case BGP_NOTIFY_CAPABILITY_ERR:
-               return lookup_msg(bgp_notify_capability_msg, subcode,
+       case BGP_NOTIFY_ROUTE_REFRESH_ERR:
+               return lookup_msg(bgp_notify_route_refresh_msg, subcode,
                                  "Unrecognized Error Subcode");
        }
        return "";
index 74cbf3a80a9d9b8e0961889db5be94a5fb8b0006..c358d4203ed4f2cb4a18466fe420affc3ec42b4d 100644 (file)
@@ -95,7 +95,7 @@ static bool ecommunity_add_val_internal(struct ecommunity *ecom,
                                        bool unique, bool overwrite,
                                        uint8_t ecom_size)
 {
-       int c, ins_idx;
+       uint32_t c, ins_idx;
        const struct ecommunity_val *eval4 = (struct ecommunity_val *)eval;
        const struct ecommunity_val_ipv6 *eval6 =
                (struct ecommunity_val_ipv6 *)eval;
@@ -113,7 +113,7 @@ static bool ecommunity_add_val_internal(struct ecommunity *ecom,
        /* check also if the extended community itself exists. */
        c = 0;
 
-       ins_idx = -1;
+       ins_idx = UINT32_MAX;
        for (uint8_t *p = ecom->val; c < ecom->size;
             p += ecom_size, c++) {
                if (unique) {
@@ -145,12 +145,12 @@ static bool ecommunity_add_val_internal(struct ecommunity *ecom,
                if (ret > 0) {
                        if (!unique)
                                break;
-                       if (ins_idx == -1)
+                       if (ins_idx == UINT32_MAX)
                                ins_idx = c;
                }
        }
 
-       if (ins_idx == -1)
+       if (ins_idx == UINT32_MAX)
                ins_idx = c;
 
        /* Add the value to the structure with numerical sorting.  */
@@ -193,7 +193,7 @@ static struct ecommunity *
 ecommunity_uniq_sort_internal(struct ecommunity *ecom,
                              unsigned short ecom_size)
 {
-       int i;
+       uint32_t i;
        struct ecommunity *new;
        const void *eval;
 
@@ -895,7 +895,7 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt)
 */
 char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
 {
-       int i;
+       uint32_t i;
        uint8_t *pnt;
        uint8_t type = 0;
        uint8_t sub_type = 0;
@@ -903,7 +903,7 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
        int str_size;
        char *str_buf;
 
-       if (ecom->size == 0)
+       if (!ecom || ecom->size == 0)
                return XCALLOC(MTYPE_ECOMMUNITY_STR, 1);
 
        /* ecom strlen + space + null term */
@@ -1176,8 +1176,8 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
 bool ecommunity_match(const struct ecommunity *ecom1,
                      const struct ecommunity *ecom2)
 {
-       int i = 0;
-       int j = 0;
+       uint32_t i = 0;
+       uint32_t j = 0;
 
        if (ecom1 == NULL && ecom2 == NULL)
                return true;
@@ -1209,7 +1209,7 @@ extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *ecom,
                                                uint8_t type, uint8_t subtype)
 {
        uint8_t *p;
-       int c;
+       uint32_t c;
 
        /* If the value already exists in the structure return 0.  */
        c = 0;
@@ -1230,7 +1230,7 @@ bool ecommunity_strip(struct ecommunity *ecom, uint8_t type,
                      uint8_t subtype)
 {
        uint8_t *p, *q, *new;
-       int c, found = 0;
+       uint32_t c, found = 0;
        /* When this is fist value, just add it.  */
        if (ecom == NULL || ecom->val == NULL)
                return false;
@@ -1278,7 +1278,7 @@ bool ecommunity_strip(struct ecommunity *ecom, uint8_t type,
 bool ecommunity_del_val(struct ecommunity *ecom, struct ecommunity_val *eval)
 {
        uint8_t *p;
-       int c, found = 0;
+       uint32_t c, found = 0;
 
        /* Make sure specified value exists. */
        if (ecom == NULL || ecom->val == NULL)
@@ -1512,7 +1512,7 @@ void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate *aggregate,
 const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw)
 {
        const uint8_t *eval;
-       int i;
+       uint32_t i;
 
        if (bw)
                *bw = 0;
index 6318e7edb1e3081994048a72636ad8aed9de662d..6d0275a0c3bab9a8b94c52207803cf39fd1184c9 100644 (file)
@@ -114,7 +114,7 @@ struct ecommunity {
        uint8_t unit_size;
 
        /* Size of Extended Communities attribute.  */
-       int size;
+       uint32_t size;
 
        /* Extended Communities value.  */
        uint8_t *val;
index 890f7963e685a265265e1d0655c93a616283ca28..88747b14b158c4d3c1f1a598dcab0a5b7af5acc1 100644 (file)
@@ -743,6 +743,7 @@ static void build_evpn_type5_route_extcomm(struct bgp *bgp_vrf,
        } else
                ecom = ecommunity_dup(&ecom_encap);
        attr->ecommunity = ecom;
+       attr->encap_tunneltype = tnl_type;
 
        /* Add the export RTs for L3VNI/VRF */
        vrf_export_rtl = bgp_vrf->vrf_export_rtl;
@@ -799,6 +800,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
 
        /* Add Encap */
        attr->ecommunity = ecommunity_dup(&ecom_encap);
+       attr->encap_tunneltype = tnl_type;
 
        /* Add the export RTs for L2VNI */
        for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom))
@@ -868,7 +870,7 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr)
        struct ecommunity ecom_tmp;
        struct ecommunity_val eval;
        uint8_t *ecom_val_ptr;
-       int i;
+       uint32_t i;
        uint8_t *pnt;
        int type = 0;
        int sub_type = 0;
@@ -1485,10 +1487,10 @@ static void update_evpn_route_entry_sync_info(struct bgp *bgp,
  * or the global route table.
  */
 static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
-                                  afi_t afi, safi_t safi, struct bgp_dest *dest,
-                                  struct attr *attr, int add,
-                                  struct bgp_path_info **pi, uint8_t flags,
-                                  uint32_t seq, bool setup_sync,
+                                  afi_t afi, safi_t safi,
+                                  struct bgp_dest *dest, struct attr *attr,
+                                  int add, struct bgp_path_info **pi,
+                                  uint8_t flags, uint32_t seq, bool vpn_rt,
                                   bool *old_is_sync)
 {
        struct bgp_path_info *tmp_pi;
@@ -1520,7 +1522,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
        /* if a local path is being added with a non-zero esi look
         * for SYNC paths from ES peers and bubble up the sync-info
         */
-       update_evpn_route_entry_sync_info(bgp, dest, attr, seq, setup_sync);
+       update_evpn_route_entry_sync_info(bgp, dest, attr, seq, vpn_rt);
 
        /* For non-GW MACs, update MAC mobility seq number, if needed. */
        if (seq && !CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW))
@@ -1612,6 +1614,14 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
                }
        }
 
+       /* MAC-IP routes in the VNI route table are linked to the
+        * destination ES
+        */
+       if (route_change && vpn_rt
+           && (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE))
+               bgp_evpn_path_es_link(tmp_pi, vpn->vni,
+                                     bgp_evpn_attr_get_esi(tmp_pi->attr));
+
        /* Return back the route entry. */
        *pi = tmp_pi;
        return route_change;
@@ -2513,7 +2523,7 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
 
        if (!pi) {
                /* Create an info */
-               (void)bgp_create_evpn_bgp_path_info(parent_pi, dest,
+               pi = bgp_create_evpn_bgp_path_info(parent_pi, dest,
                                                    parent_pi->attr);
        } else {
                if (attrhash_cmp(pi->attr, parent_pi->attr)
@@ -2539,6 +2549,11 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
                pi->uptime = bgp_clock();
        }
 
+       /* MAC-IP routes in the VNI table are linked to the destination ES */
+       if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
+               bgp_evpn_path_es_link(pi, vpn->vni,
+                                     bgp_evpn_attr_get_esi(pi->attr));
+
        /* Perform route selection and update zebra, if required. */
        ret = evpn_route_select_install(bgp, vpn, dest);
 
@@ -2695,7 +2710,7 @@ static int is_route_matching_for_vrf(struct bgp *bgp_vrf,
 {
        struct attr *attr = pi->attr;
        struct ecommunity *ecom;
-       int i;
+       uint32_t i;
 
        assert(attr);
        /* Route should have valid RT to be even considered. */
@@ -2762,7 +2777,7 @@ static int is_route_matching_for_vni(struct bgp *bgp, struct bgpevpn *vpn,
 {
        struct attr *attr = pi->attr;
        struct ecommunity *ecom;
-       int i;
+       uint32_t i;
 
        assert(attr);
        /* Route should have valid RT to be even considered. */
@@ -2852,6 +2867,55 @@ static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf,
        return 0;
 }
 
+/* don't import hosts that are locally attached */
+static inline bool
+bgp_evpn_skip_vrf_import_of_local_es(const struct prefix_evpn *evp,
+                                    struct bgp_path_info *pi, int install)
+{
+       esi_t *esi;
+       struct in_addr nh;
+
+       if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+               esi = bgp_evpn_attr_get_esi(pi->attr);
+
+               /* Don't import routes that point to a local destination */
+               if (bgp_evpn_attr_is_local_es(pi->attr)) {
+                       if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) {
+                               char esi_buf[ESI_STR_LEN];
+
+                               zlog_debug(
+                                       "vrf %s of evpn prefix %pFX skipped, local es %s",
+                                       install ? "import" : "unimport", evp,
+                                       esi_to_str(esi, esi_buf,
+                                                  sizeof(esi_buf)));
+                       }
+                       return true;
+               }
+
+               /* Don't import routes with ES as destination if the nexthop
+                * has not been advertised via the EAD-ES
+                */
+               if (pi->attr)
+                       nh = pi->attr->nexthop;
+               else
+                       nh.s_addr = INADDR_ANY;
+               if (install && !bgp_evpn_es_is_vtep_active(esi, nh)) {
+                       if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) {
+                               char esi_buf[ESI_STR_LEN];
+
+                               zlog_debug(
+                                       "vrf %s of evpn prefix %pFX skipped, nh %pI4 inactive in es %s",
+                                       install ? "import" : "unimport", evp,
+                                       &nh,
+                                       esi_to_str(esi, esi_buf,
+                                                  sizeof(esi_buf)));
+                       }
+                       return true;
+               }
+       }
+       return false;
+}
+
 /*
  * Install or uninstall mac-ip routes are appropriate for this
  * particular VRF.
@@ -2909,6 +2973,12 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
                                      && pi->sub_type == BGP_ROUTE_NORMAL))
                                        continue;
 
+                               /* don't import hosts that are locally attached
+                                */
+                               if (bgp_evpn_skip_vrf_import_of_local_es(
+                                           evp, pi, install))
+                                       continue;
+
                                if (is_route_matching_for_vrf(bgp_vrf, pi)) {
                                        if (bgp_evpn_route_rmac_self_check(
                                                                bgp_vrf, evp, pi))
@@ -3115,6 +3185,10 @@ static int install_uninstall_route_in_vrfs(struct bgp *bgp_def, afi_t afi,
                 || is_evpn_prefix_ipaddr_v6(evp)))
                return 0;
 
+       /* don't import hosts that are locally attached */
+       if (bgp_evpn_skip_vrf_import_of_local_es(evp, pi, install))
+               return 0;
+
        for (ALL_LIST_ELEMENTS(vrfs, node, nnode, bgp_vrf)) {
                int ret;
 
@@ -3177,14 +3251,16 @@ static int install_uninstall_route_in_vnis(struct bgp *bgp, afi_t afi,
 /*
  * Install or uninstall route for appropriate VNIs/ESIs.
  */
-static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
-                                       const struct prefix *p,
-                                       struct bgp_path_info *pi, int import)
+static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi,
+                                           safi_t safi, const struct prefix *p,
+                                           struct bgp_path_info *pi,
+                                           int import, bool in_vni_rt,
+                                           bool in_vrf_rt)
 {
        struct prefix_evpn *evp = (struct prefix_evpn *)p;
        struct attr *attr = pi->attr;
        struct ecommunity *ecom;
-       int i;
+       uint32_t i;
        struct prefix_evpn ad_evp;
 
        assert(attr);
@@ -3241,13 +3317,13 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
                    evp->prefix.route_type == BGP_EVPN_AD_ROUTE ||
                    evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) {
 
-                       irt = lookup_import_rt(bgp, eval);
+                       irt = in_vni_rt ? lookup_import_rt(bgp, eval) : NULL;
                        if (irt)
                                install_uninstall_route_in_vnis(
                                        bgp, afi, safi, evp, pi, irt->vnis,
                                        import);
 
-                       vrf_irt = lookup_vrf_import_rt(eval);
+                       vrf_irt = in_vrf_rt ? lookup_vrf_import_rt(eval) : NULL;
                        if (vrf_irt)
                                install_uninstall_route_in_vrfs(
                                        bgp, afi, safi, evp, pi, vrf_irt->vrfs,
@@ -3266,8 +3342,11 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
                            || type == ECOMMUNITY_ENCODE_IP) {
                                memcpy(&eval_tmp, eval, ecom->unit_size);
                                mask_ecom_global_admin(&eval_tmp, eval);
-                               irt = lookup_import_rt(bgp, &eval_tmp);
-                               vrf_irt = lookup_vrf_import_rt(&eval_tmp);
+                               if (in_vni_rt)
+                                       irt = lookup_import_rt(bgp, &eval_tmp);
+                               if (in_vrf_rt)
+                                       vrf_irt =
+                                               lookup_vrf_import_rt(&eval_tmp);
                        }
 
                        if (irt)
@@ -3296,6 +3375,31 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
        return 0;
 }
 
+/*
+ * Install or uninstall route for appropriate VNIs/ESIs.
+ */
+static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
+                                       const struct prefix *p,
+                                       struct bgp_path_info *pi, int import)
+{
+       return bgp_evpn_install_uninstall_table(bgp, afi, safi, p, pi, import,
+                                               true, true);
+}
+
+/* Import the pi into vrf routing tables */
+void bgp_evpn_import_route_in_vrfs(struct bgp_path_info *pi, int import)
+{
+       struct bgp *bgp_evpn;
+
+       bgp_evpn = bgp_get_evpn();
+       if (!bgp_evpn)
+               return;
+
+       bgp_evpn_install_uninstall_table(bgp_evpn, AFI_L2VPN, SAFI_EVPN,
+                                        &pi->net->p, pi, import, false /*vpn*/,
+                                        true /*vrf*/);
+}
+
 /*
  * delete and withdraw all ipv4 and ipv6 routes in the vrf table as type-5
  * routes
@@ -4802,7 +4906,7 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
  */
 void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf)
 {
-       int i = 0;
+       uint32_t i = 0;
        struct ecommunity_val *eval = NULL;
        struct listnode *node = NULL, *nnode = NULL;
        struct ecommunity *ecom = NULL;
@@ -4822,7 +4926,7 @@ void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf)
  */
 void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *bgp_vrf)
 {
-       int i;
+       uint32_t i;
        struct ecommunity_val *eval;
        struct listnode *node, *nnode;
        struct ecommunity *ecom;
@@ -4859,7 +4963,7 @@ void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *bgp_vrf)
  */
 void bgp_evpn_map_vni_to_its_rts(struct bgp *bgp, struct bgpevpn *vpn)
 {
-       int i;
+       uint32_t i;
        struct ecommunity_val *eval;
        struct listnode *node, *nnode;
        struct ecommunity *ecom;
@@ -4879,7 +4983,7 @@ void bgp_evpn_map_vni_to_its_rts(struct bgp *bgp, struct bgpevpn *vpn)
  */
 void bgp_evpn_unmap_vni_from_its_rts(struct bgp *bgp, struct bgpevpn *vpn)
 {
-       int i;
+       uint32_t i;
        struct ecommunity_val *eval;
        struct listnode *node, *nnode;
        struct ecommunity *ecom;
index ba43191ebf356fdb55040f8a31e606c3aa27c178..29d3d2c62f152fcd6d2972b7f0f874ceeaac8d41 100644 (file)
@@ -77,17 +77,16 @@ static inline int advertise_type5_routes(struct bgp *bgp_vrf,
 }
 
 /* Flag if the route's parent is a EVPN route. */
-static inline int is_route_parent_evpn(struct bgp_path_info *ri)
+static inline struct bgp_path_info *
+get_route_parent_evpn(struct bgp_path_info *ri)
 {
        struct bgp_path_info *parent_ri;
-       struct bgp_table *table;
-       struct bgp_dest *dest;
 
        /* If not imported (or doesn't have a parent), bail. */
        if (ri->sub_type != BGP_ROUTE_IMPORTED ||
            !ri->extra ||
            !ri->extra->parent)
-               return 0;
+               return NULL;
 
        /* Determine parent recursively */
        for (parent_ri = ri->extra->parent;
@@ -95,6 +94,20 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri)
             parent_ri = parent_ri->extra->parent)
                ;
 
+       return parent_ri;
+}
+
+/* Flag if the route's parent is a EVPN route. */
+static inline int is_route_parent_evpn(struct bgp_path_info *ri)
+{
+       struct bgp_path_info *parent_ri;
+       struct bgp_table *table;
+       struct bgp_dest *dest;
+
+       parent_ri = get_route_parent_evpn(ri);
+       if (!parent_ri)
+               return 0;
+
        /* See if of family L2VPN/EVPN */
        dest = parent_ri->net;
        if (!dest)
index bf9a2f849ad38b299635448a4b52062235d161ae..b5678af91abbfda75961350d473c5a2a76bc55de 100644 (file)
@@ -48,6 +48,8 @@
 #include "bgpd/bgp_zebra.h"
 #include "bgpd/bgp_addpath.h"
 #include "bgpd/bgp_label.h"
+#include "bgpd/bgp_nht.h"
+#include "bgpd/bgp_mpath.h"
 
 static void bgp_evpn_local_es_down(struct bgp *bgp,
                struct bgp_evpn_es *es);
@@ -63,6 +65,13 @@ static void bgp_evpn_es_vtep_del(struct bgp *bgp,
 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es);
 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es);
 static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi);
+static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es *es);
+static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es *es);
+static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi);
+static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller);
+static void
+bgp_evpn_es_path_update_on_vtep_chg(struct bgp_evpn_es_vtep *es_vtep,
+                                   bool active);
 
 esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
 
@@ -1070,7 +1079,7 @@ int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi,
        /* EAD route prefix doesn't include the nexthop in the global
         * table
         */
-       vtep_ip.s_addr = 0;
+       vtep_ip.s_addr = INADDR_ANY;
        build_evpn_type1_prefix(&p, eth_tag, &esi, vtep_ip);
        /* Process the route. */
        if (attr) {
@@ -1228,6 +1237,15 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp,
                /* send remote ES to zebra */
                bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active);
 
+               /* The NHG is updated first for efficient failover handling.
+                * Note the NHG can be de-activated while there are bgp
+                * routes referencing it. Zebra is capable of handling that
+                * elegantly by holding the NHG till all routes using it are
+                * removed.
+                */
+               bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep->es);
+               bgp_evpn_es_path_update_on_vtep_chg(es_vtep, new_active);
+
                /* queue up the es for background consistency checks */
                bgp_evpn_es_cons_checks_pend_add(es_vtep->es);
        }
@@ -1303,6 +1321,164 @@ static void bgp_evpn_es_vtep_del(struct bgp *bgp,
                bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr);
 }
 
+bool bgp_evpn_es_is_vtep_active(esi_t *esi, struct in_addr nh)
+{
+       struct bgp_evpn_es *es;
+       struct bgp_evpn_es_vtep *es_vtep;
+       struct listnode *node = NULL;
+       bool rc = false;
+
+       if (!memcmp(esi, zero_esi, sizeof(*esi)) || !nh.s_addr)
+               return true;
+
+       es = bgp_evpn_es_find(esi);
+       if (!es)
+               return false;
+
+       for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
+               if (es_vtep->vtep_ip.s_addr == nh.s_addr) {
+                       if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
+                               rc = true;
+                       break;
+               }
+       }
+       return rc;
+}
+
+/********************** ES MAC-IP paths *************************************
+ * MAC-IP routes in the VNI routing table are linked to the destination
+ * ES for efficient updates on ES changes (such as VTEP add/del).
+ ****************************************************************************/
+void bgp_evpn_path_es_info_free(struct bgp_path_es_info *es_info)
+{
+       bgp_evpn_path_es_unlink(es_info);
+       XFREE(MTYPE_BGP_EVPN_PATH_ES_INFO, es_info);
+}
+
+static struct bgp_path_es_info *
+bgp_evpn_path_es_info_new(struct bgp_path_info *pi, vni_t vni)
+{
+       struct bgp_path_info_extra *e;
+
+       e = bgp_path_info_extra_get(pi);
+
+       /* If es_info doesn't exist allocate it */
+       if (!e->es_info) {
+               e->es_info = XCALLOC(MTYPE_BGP_EVPN_PATH_ES_INFO,
+                                    sizeof(struct bgp_path_es_info));
+               e->es_info->pi = pi;
+               e->es_info->vni = vni;
+       }
+
+       return e->es_info;
+}
+
+void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info)
+{
+       struct bgp_evpn_es *es = es_info->es;
+       struct bgp_path_info *pi;
+
+       if (!es)
+               return;
+
+       pi = es_info->pi;
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
+               zlog_debug("vni %u path %pFX unlinked from es %s", es_info->vni,
+                          &pi->net->p, es->esi_str);
+
+       list_delete_node(es->macip_path_list, &es_info->es_listnode);
+       es_info->es = NULL;
+
+       /* if there are no other references against the ES it
+        * needs to be freed
+        */
+       bgp_evpn_es_free(es, __func__);
+
+       /* Note we don't free the path es_info on unlink; it will be freed up
+        * along with the path.
+        */
+}
+
+void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi)
+{
+       struct bgp_path_es_info *es_info;
+       struct bgp_evpn_es *es;
+       struct bgp *bgp_evpn = bgp_get_evpn();
+
+       es_info = pi->extra ? pi->extra->es_info : NULL;
+       /* if the esi is zero just unlink the path from the old es */
+       if (!esi || !memcmp(esi, zero_esi, sizeof(*esi))) {
+               if (es_info)
+                       bgp_evpn_path_es_unlink(es_info);
+               return;
+       }
+
+       if (!bgp_evpn)
+               return;
+
+       /* setup es_info against the path if it doesn't aleady exist */
+       if (!es_info)
+               es_info = bgp_evpn_path_es_info_new(pi, vni);
+
+       /* find-create ES */
+       es = bgp_evpn_es_find(esi);
+       if (!es)
+               es = bgp_evpn_es_new(bgp_evpn, esi);
+
+       /* dup check */
+       if (es_info->es == es)
+               return;
+
+       /* unlink old ES if any */
+       bgp_evpn_path_es_unlink(es_info);
+
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
+               zlog_debug("vni %u path %pFX linked to es %s", vni, &pi->net->p,
+                          es->esi_str);
+
+       /* link mac-ip path to the new destination ES */
+       es_info->es = es;
+       listnode_init(&es_info->es_listnode, es_info);
+       listnode_add(es->macip_path_list, &es_info->es_listnode);
+}
+
+static void
+bgp_evpn_es_path_update_on_vtep_chg(struct bgp_evpn_es_vtep *es_vtep,
+                                   bool active)
+{
+       struct listnode *node;
+       struct bgp_path_es_info *es_info;
+       struct bgp_path_info *pi;
+       struct bgp_path_info *parent_pi;
+       struct bgp_evpn_es *es = es_vtep->es;
+
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
+               zlog_debug("update paths linked to es %s on vtep chg",
+                          es->esi_str);
+
+       for (ALL_LIST_ELEMENTS_RO(es->macip_path_list, node, es_info)) {
+               pi = es_info->pi;
+               if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID))
+                       continue;
+
+               if (pi->sub_type != BGP_ROUTE_IMPORTED)
+                       continue;
+
+               parent_pi = pi->extra ? pi->extra->parent : NULL;
+               if (!parent_pi || !parent_pi->attr)
+                       continue;
+
+               if (es_vtep->vtep_ip.s_addr != parent_pi->attr->nexthop.s_addr)
+                       continue;
+
+               if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
+                       zlog_debug(
+                               "update path %pFX linked to es %s on vtep chg",
+                               &parent_pi->net->p, es->esi_str);
+               bgp_evpn_import_route_in_vrfs(parent_pi, active ? 1 : 0);
+       }
+}
+
 /* compare ES-IDs for the global ES RB tree */
 static int bgp_es_rb_cmp(const struct bgp_evpn_es *es1,
                const struct bgp_evpn_es *es2)
@@ -1351,6 +1527,14 @@ static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi)
        es->es_evi_list = list_new();
        listset_app_node_mem(es->es_evi_list);
 
+       /* Initialise the ES-VRF list used for L3NHG management */
+       es->es_vrf_list = list_new();
+       listset_app_node_mem(es->es_vrf_list);
+
+       /* Initialise the route list used for efficient event handling */
+       es->macip_path_list = list_new();
+       listset_app_node_mem(es->macip_path_list);
+
        QOBJ_REG(es, bgp_evpn_es);
 
        return es;
@@ -1362,7 +1546,8 @@ static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi)
  */
 static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller)
 {
-       if (es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE))
+       if ((es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE))
+           || listcount(es->macip_path_list))
                return;
 
        if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
@@ -1370,7 +1555,9 @@ static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller)
 
        /* cleanup resources maintained against the ES */
        list_delete(&es->es_evi_list);
+       list_delete(&es->es_vrf_list);
        list_delete(&es->es_vtep_list);
+       list_delete(&es->macip_path_list);
        bgp_table_unlock(es->route_table);
 
        /* remove the entry from various databases */
@@ -1809,6 +1996,10 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
                                                 ip_buf, sizeof(ip_buf)));
                json_object_int_add(json, "remoteVniCount",
                                es->remote_es_evi_cnt);
+               json_object_int_add(json, "vrfCount",
+                                   listcount(es->es_vrf_list));
+               json_object_int_add(json, "macipPathCount",
+                                   listcount(es->macip_path_list));
                json_object_int_add(json, "inconsistentVniVtepCount",
                                es->incons_evi_vtep_cnt);
                if (listcount(es->es_vtep_list)) {
@@ -1853,6 +2044,9 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
                vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
                vty_out(vty, " Remote VNI Count: %d\n",
                                es->remote_es_evi_cnt);
+               vty_out(vty, " VRF Count: %d\n", listcount(es->es_vrf_list));
+               vty_out(vty, " MACIP Path Count: %d\n",
+                       listcount(es->macip_path_list));
                vty_out(vty, " Inconsistent VNI VTEP Count: %d\n",
                                es->incons_evi_vtep_cnt);
                if (es->inconsistencies) {
@@ -1940,6 +2134,517 @@ void bgp_evpn_es_show_esi(struct vty *vty, esi_t *esi, bool uj)
        }
 }
 
+/*****************************************************************************/
+/* Ethernet Segment to VRF association -
+ * 1. Each ES-EVI entry is associated with a tenant VRF. This associaton
+ * triggers the creation of an ES-VRF entry.
+ * 2. The ES-VRF entry is maintained for the purpose of L3-NHG creation
+ * 3. Type-2/MAC-IP routes are imported into a tenant VRF and programmed as
+ * a /32 or host route entry in the dataplane. If the destination of
+ * the host route is a remote-ES the route is programmed with the
+ * corresponding (keyed in by {vrf,ES-id}) L3-NHG.
+ * 4. The reason for this indirection (route->L3-NHG, L3-NHG->list-of-VTEPs)
+ * is to avoid route updates to the dplane when a remote-ES link flaps i.e.
+ * instead of updating all the dependent routes the NHG's contents are updated.
+ * This reduces the amount of datplane updates (nhg updates vs. route updates)
+ * allowing for a faster failover.
+ *
+ * XXX - can the L3 SVI index change without change in vpn->bgp_vrf
+ * association? If yes we need to handle that by updating all the L3 NHGs
+ * in that VRF.
+ */
+/******************************** L3 NHG management *************************/
+static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf *es_vrf,
+                                             bool v4_nhg)
+{
+       uint32_t nhg_id = v4_nhg ? es_vrf->nhg_id : es_vrf->v6_nhg_id;
+       struct bgp_evpn_es *es = es_vrf->es;
+       struct listnode *node;
+       struct bgp_evpn_es_vtep *es_vtep;
+       struct nexthop nh;
+       struct zapi_nexthop *api_nh;
+       struct zapi_nhg api_nhg = {};
+
+       /* Skip installation of L3-NHG if host routes used */
+       if (!nhg_id)
+               return;
+
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+               zlog_debug("es %s vrf %u %s nhg %u to zebra", es->esi_str,
+                          es_vrf->bgp_vrf->vrf_id,
+                          v4_nhg ? "v4_nhg" : "v6_nhg", nhg_id);
+
+       /* only the gateway ip changes for each NH. rest of the params
+        * are constant
+        */
+       memset(&nh, 0, sizeof(nh));
+       nh.vrf_id = es_vrf->bgp_vrf->vrf_id;
+       nh.flags = NEXTHOP_FLAG_ONLINK;
+       nh.ifindex = es_vrf->bgp_vrf->l3vni_svi_ifindex;
+       nh.weight = 1;
+       nh.type =
+               v4_nhg ? NEXTHOP_TYPE_IPV4_IFINDEX : NEXTHOP_TYPE_IPV6_IFINDEX;
+
+       api_nhg.id = nhg_id;
+       for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
+               if (!CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
+                       continue;
+
+               /* overwrite the gw */
+               if (v4_nhg)
+                       nh.gate.ipv4 = es_vtep->vtep_ip;
+               else
+                       ipv4_to_ipv4_mapped_ipv6(&nh.gate.ipv6,
+                                                es_vtep->vtep_ip);
+
+               /* convert to zapi format */
+               api_nh = &api_nhg.nexthops[api_nhg.nexthop_num];
+               zapi_nexthop_from_nexthop(api_nh, &nh);
+
+               ++api_nhg.nexthop_num;
+               if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+                       zlog_debug("nhg %u vtep %pI4 l3-svi %d", api_nhg.id,
+                                  &es_vtep->vtep_ip,
+                                  es_vrf->bgp_vrf->l3vni_svi_ifindex);
+       }
+
+       if (!api_nhg.nexthop_num)
+               return;
+
+       if (api_nhg.nexthop_num > MULTIPATH_NUM)
+               return;
+
+       zclient_nhg_send(zclient, ZEBRA_NHG_ADD, &api_nhg);
+}
+
+static bool bgp_evpn_l3nhg_zebra_ok(struct bgp_evpn_es_vrf *es_vrf)
+{
+       if (!bgp_mh_info->host_routes_use_l3nhg && !bgp_mh_info->install_l3nhg)
+               return false;
+
+       /* Check socket. */
+       if (!zclient || zclient->sock < 0)
+               return false;
+
+       return true;
+}
+
+static void bgp_evpn_l3nhg_zebra_add(struct bgp_evpn_es_vrf *es_vrf)
+{
+       if (!bgp_evpn_l3nhg_zebra_ok(es_vrf))
+               return;
+
+       bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf, true /*v4_nhg*/);
+       bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf, false /*v4_nhg*/);
+}
+
+static void bgp_evpn_l3nhg_zebra_del_v4_or_v6(struct bgp_evpn_es_vrf *es_vrf,
+                                             bool v4_nhg)
+{
+       struct zapi_nhg api_nhg = {};
+
+       api_nhg.id = v4_nhg ? es_vrf->nhg_id : es_vrf->v6_nhg_id;
+
+       /* Skip installation of L3-NHG if host routes used */
+       if (!api_nhg.id)
+               return;
+
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+               zlog_debug("es %s vrf %u %s nhg %u to zebra",
+                          es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id,
+                          v4_nhg ? "v4_nhg" : "v6_nhg", api_nhg.id);
+
+       zclient_nhg_send(zclient, ZEBRA_NHG_DEL, &api_nhg);
+}
+
+static void bgp_evpn_l3nhg_zebra_del(struct bgp_evpn_es_vrf *es_vrf)
+{
+       if (!bgp_evpn_l3nhg_zebra_ok(es_vrf))
+               return;
+
+       bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf, true /*v4_nhg*/);
+       bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf, false /*v4_nhg*/);
+}
+
+static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf *es_vrf)
+{
+       if (!(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE))
+               return;
+
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+               zlog_debug("es %s vrf %u nhg %u de-activate",
+                          es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id,
+                          es_vrf->nhg_id);
+       bgp_evpn_l3nhg_zebra_del(es_vrf);
+       es_vrf->flags &= ~BGP_EVPNES_VRF_NHG_ACTIVE;
+}
+
+static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf *es_vrf, bool update)
+{
+       if (!bgp_evpn_es_get_active_vtep_cnt(es_vrf->es)) {
+               bgp_evpn_l3nhg_deactivate(es_vrf);
+               return;
+       }
+
+       if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) {
+               if (!update)
+                       return;
+       } else {
+               if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+                       zlog_debug("es %s vrf %u nhg %u activate",
+                                  es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id,
+                                  es_vrf->nhg_id);
+               es_vrf->flags |= BGP_EVPNES_VRF_NHG_ACTIVE;
+       }
+
+       bgp_evpn_l3nhg_zebra_add(es_vrf);
+}
+
+/* when a VTEP is activated or de-activated against an ES associated
+ * VRFs' NHG needs to be updated
+ */
+static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es *es)
+{
+       struct bgp_evpn_es_vrf *es_vrf;
+       struct listnode *es_vrf_node;
+
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+               zlog_debug("es %s nhg update on vtep chg", es->esi_str);
+
+       for (ALL_LIST_ELEMENTS_RO(es->es_vrf_list, es_vrf_node, es_vrf))
+               bgp_evpn_l3nhg_activate(es_vrf, true /* update */);
+}
+
+/* compare ES-IDs for the ES-VRF RB tree maintained per-VRF */
+static int bgp_es_vrf_rb_cmp(const struct bgp_evpn_es_vrf *es_vrf1,
+                            const struct bgp_evpn_es_vrf *es_vrf2)
+{
+       return memcmp(&es_vrf1->es->esi, &es_vrf2->es->esi, ESI_BYTES);
+}
+RB_GENERATE(bgp_es_vrf_rb_head, bgp_evpn_es_vrf, rb_node, bgp_es_vrf_rb_cmp);
+
+/* Initialize the ES tables maintained per-tenant vrf */
+void bgp_evpn_vrf_es_init(struct bgp *bgp_vrf)
+{
+       /* Initialize the ES-VRF RB tree */
+       RB_INIT(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree);
+}
+
+/* find the ES-VRF in the per-VRF RB tree */
+static struct bgp_evpn_es_vrf *bgp_evpn_es_vrf_find(struct bgp_evpn_es *es,
+                                                   struct bgp *bgp_vrf)
+{
+       struct bgp_evpn_es_vrf es_vrf;
+
+       es_vrf.es = es;
+
+       return RB_FIND(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree, &es_vrf);
+}
+
+/* allocate a new ES-VRF and setup L3NHG for it */
+static struct bgp_evpn_es_vrf *bgp_evpn_es_vrf_create(struct bgp_evpn_es *es,
+                                                     struct bgp *bgp_vrf)
+{
+       struct bgp_evpn_es_vrf *es_vrf;
+
+       es_vrf = XCALLOC(MTYPE_BGP_EVPN_ES_VRF, sizeof(*es_vrf));
+
+       es_vrf->es = es;
+       es_vrf->bgp_vrf = bgp_vrf;
+
+       /* insert into the VRF-ESI rb tree */
+       if (RB_INSERT(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree, es_vrf)) {
+               XFREE(MTYPE_BGP_EVPN_ES_VRF, es_vrf);
+               return NULL;
+       }
+
+       /* add to the ES's VRF list */
+       listnode_init(&es_vrf->es_listnode, es_vrf);
+       listnode_add(es->es_vrf_list, &es_vrf->es_listnode);
+
+       /* setup the L3 NHG id for the ES */
+       es_vrf->nhg_id = bgp_l3nhg_id_alloc();
+       es_vrf->v6_nhg_id = bgp_l3nhg_id_alloc();
+
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+               zlog_debug("es %s vrf %u nhg %u v6_nhg %d create", es->esi_str,
+                          bgp_vrf->vrf_id, es_vrf->nhg_id, es_vrf->v6_nhg_id);
+       bgp_evpn_l3nhg_activate(es_vrf, false /* update */);
+
+       return es_vrf;
+}
+
+/* remove the L3-NHG associated with the ES-VRF and free it */
+static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf *es_vrf)
+{
+       struct bgp_evpn_es *es = es_vrf->es;
+       struct bgp *bgp_vrf = es_vrf->bgp_vrf;
+
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+               zlog_debug("es %s vrf %u nhg %u delete", es->esi_str,
+                          bgp_vrf->vrf_id, es_vrf->nhg_id);
+
+       /* Remove the NHG resources */
+       bgp_evpn_l3nhg_deactivate(es_vrf);
+       if (es_vrf->nhg_id)
+               bgp_l3nhg_id_free(es_vrf->nhg_id);
+       es_vrf->nhg_id = 0;
+       if (es_vrf->v6_nhg_id)
+               bgp_l3nhg_id_free(es_vrf->v6_nhg_id);
+       es_vrf->v6_nhg_id = 0;
+
+       /* remove from the ES's VRF list */
+       list_delete_node(es->es_vrf_list, &es_vrf->es_listnode);
+
+       /* remove from the VRF-ESI rb tree */
+       RB_REMOVE(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree, es_vrf);
+
+       XFREE(MTYPE_BGP_EVPN_ES_VRF, es_vrf);
+}
+
+/* deref and delete if there are no references */
+void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi *es_evi)
+{
+       struct bgp_evpn_es_vrf *es_vrf = es_evi->es_vrf;
+
+       if (!es_vrf)
+               return;
+
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+               zlog_debug("es-evi %s vni %u vrf %u de-ref",
+                          es_evi->es->esi_str, es_evi->vpn->vni,
+                          es_vrf->bgp_vrf->vrf_id);
+
+       es_evi->es_vrf = NULL;
+       if (es_vrf->ref_cnt)
+               --es_vrf->ref_cnt;
+
+       if (!es_vrf->ref_cnt)
+               bgp_evpn_es_vrf_delete(es_vrf);
+}
+
+/* find or create and reference */
+void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi *es_evi, struct bgp *bgp_vrf)
+{
+       struct bgp_evpn_es *es = es_evi->es;
+       struct bgp_evpn_es_vrf *es_vrf = es_evi->es_vrf;
+       struct bgp *old_bgp_vrf = NULL;
+
+       if (es_vrf)
+               old_bgp_vrf = es_vrf->bgp_vrf;
+
+       if (old_bgp_vrf == bgp_vrf)
+               return;
+
+       /* deref the old ES-VRF */
+       bgp_evpn_es_vrf_deref(es_evi);
+
+       if (!bgp_vrf)
+               return;
+
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+               zlog_debug("es-evi %s vni %u vrf %u ref", es_evi->es->esi_str,
+                          es_evi->vpn->vni, bgp_vrf->vrf_id);
+
+       /* find-create the new ES-VRF */
+       es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf);
+       if (!es_vrf)
+               es_vrf = bgp_evpn_es_vrf_create(es, bgp_vrf);
+       if (!es_vrf)
+               return;
+
+       es_evi->es_vrf = es_vrf;
+       ++es_vrf->ref_cnt;
+}
+
+/* When the L2-VNI is associated with a L3-VNI/VRF update all the
+ * associated ES-EVI entries
+ */
+void bgp_evpn_es_evi_vrf_deref(struct bgpevpn *vpn)
+{
+       struct bgp_evpn_es_evi *es_evi;
+
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+               zlog_debug("es-vrf de-ref for vni %u", vpn->vni);
+
+       RB_FOREACH (es_evi, bgp_es_evi_rb_head, &vpn->es_evi_rb_tree)
+               bgp_evpn_es_vrf_deref(es_evi);
+}
+void bgp_evpn_es_evi_vrf_ref(struct bgpevpn *vpn)
+{
+       struct bgp_evpn_es_evi *es_evi;
+
+       if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+               zlog_debug("es-vrf ref for vni %u", vpn->vni);
+
+       RB_FOREACH (es_evi, bgp_es_evi_rb_head, &vpn->es_evi_rb_tree)
+               bgp_evpn_es_vrf_ref(es_evi, vpn->bgp_vrf);
+}
+
+/* returns false if legacy-exploded mp needs to be used for route install */
+bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,
+                             uint32_t *nhg_p)
+{
+       esi_t *esi;
+       struct bgp_evpn_es *es;
+       struct bgp_evpn_es_vrf *es_vrf;
+       struct bgp_path_info *parent_pi;
+       struct bgp_node *rn;
+       struct prefix_evpn *evp;
+       struct bgp_path_info *mpinfo;
+
+       *nhg_p = 0;
+
+       /* L3NHG support is disabled, use legacy-exploded multipath */
+       if (!bgp_mh_info->host_routes_use_l3nhg)
+               return false;
+
+       parent_pi = get_route_parent_evpn(pi);
+       if (!parent_pi)
+               return false;
+
+       rn = parent_pi->net;
+       if (!rn)
+               return false;
+
+       evp = (struct prefix_evpn *)&rn->p;
+       if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
+               return false;
+
+       /* non-es path, use legacy-exploded multipath */
+       esi = bgp_evpn_attr_get_esi(parent_pi->attr);
+       if (!memcmp(esi, zero_esi, sizeof(*esi)))
+               return false;
+
+       /* if the ES-VRF is not setup or if the NHG has not been installed
+        * we cannot install the route yet, return a 0-NHG to indicate
+        * that
+        */
+       es = bgp_evpn_es_find(esi);
+       if (!es)
+               return true;
+       es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf);
+       if (!es_vrf || !(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE))
+               return true;
+
+       /* this needs to be set the v6NHG if v6route */
+       if (is_evpn_prefix_ipaddr_v6(evp))
+               *nhg_p = es_vrf->v6_nhg_id;
+       else
+               *nhg_p = es_vrf->nhg_id;
+
+       for (mpinfo = bgp_path_info_mpath_next(pi); mpinfo;
+            mpinfo = bgp_path_info_mpath_next(mpinfo)) {
+               /* if any of the paths of have a different ESI we can't use
+                * the NHG associated with the ES. fallback to legacy-exploded
+                * multipath
+                */
+               if (memcmp(esi, bgp_evpn_attr_get_esi(mpinfo->attr),
+                          sizeof(*esi)))
+                       return false;
+       }
+
+       return true;
+}
+
+static void bgp_evpn_es_vrf_show_entry(struct vty *vty,
+                                      struct bgp_evpn_es_vrf *es_vrf,
+                                      json_object *json)
+{
+       struct bgp_evpn_es *es = es_vrf->es;
+       struct bgp *bgp_vrf = es_vrf->bgp_vrf;
+
+       if (json) {
+               json_object *json_types;
+
+               json_object_string_add(json, "esi", es->esi_str);
+               json_object_string_add(json, "vrf", bgp_vrf->name);
+
+               if (es_vrf->flags & (BGP_EVPNES_VRF_NHG_ACTIVE)) {
+                       json_types = json_object_new_array();
+                       if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)
+                               json_array_string_add(json_types, "active");
+                       json_object_object_add(json, "flags", json_types);
+               }
+
+               json_object_int_add(json, "ipv4NHG", es_vrf->nhg_id);
+               json_object_int_add(json, "ipv6NHG", es_vrf->v6_nhg_id);
+               json_object_int_add(json, "refCount", es_vrf->ref_cnt);
+       } else {
+               char flags_str[4];
+
+               flags_str[0] = '\0';
+               if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)
+                       strlcat(flags_str, "A", sizeof(flags_str));
+
+               vty_out(vty, "%-30s %-15s %-5s %-8u %-8u %u\n", es->esi_str,
+                       bgp_vrf->name, flags_str, es_vrf->nhg_id,
+                       es_vrf->v6_nhg_id, es_vrf->ref_cnt);
+       }
+}
+
+static void bgp_evpn_es_vrf_show_es(struct vty *vty, json_object *json_array,
+                                   struct bgp_evpn_es *es)
+{
+       json_object *json = NULL;
+       struct listnode *es_vrf_node;
+       struct bgp_evpn_es_vrf *es_vrf;
+
+       for (ALL_LIST_ELEMENTS_RO(es->es_vrf_list, es_vrf_node, es_vrf)) {
+               /* create a separate json object for each ES-VRF */
+               if (json_array)
+                       json = json_object_new_object();
+               bgp_evpn_es_vrf_show_entry(vty, es_vrf, json);
+               /* add ES-VRF to the json array */
+               if (json_array)
+                       json_object_array_add(json_array, json);
+       }
+}
+
+/* Display all ES VRFs */
+void bgp_evpn_es_vrf_show(struct vty *vty, bool uj, struct bgp_evpn_es *es)
+{
+       json_object *json_array = NULL;
+
+       if (uj) {
+               /* create an array of ESs */
+               json_array = json_object_new_array();
+       } else {
+               vty_out(vty, "ES-VRF Flags: A Active\n");
+               vty_out(vty, "%-30s %-15s %-5s %-8s %-8s %s\n", "ESI", "VRF",
+                       "Flags", "IPv4-NHG", "IPv6-NHG", "Ref");
+       }
+
+       if (es) {
+               bgp_evpn_es_vrf_show_es(vty, json_array, es);
+       } else {
+               RB_FOREACH (es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree)
+                       bgp_evpn_es_vrf_show_es(vty, json_array, es);
+       }
+
+       /* print the array of json-ESs */
+       if (uj) {
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json_array, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json_array);
+       }
+}
+
+/* Display specific ES VRF */
+void bgp_evpn_es_vrf_show_esi(struct vty *vty, esi_t *esi, bool uj)
+{
+       struct bgp_evpn_es *es;
+
+       es = bgp_evpn_es_find(esi);
+       if (es) {
+               bgp_evpn_es_vrf_show(vty, uj, es);
+       } else {
+               if (!uj)
+                       vty_out(vty, "ESI not found\n");
+       }
+}
+
 /*****************************************************************************/
 /* Ethernet Segment to EVI association -
  * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
@@ -2152,6 +2857,8 @@ static struct bgp_evpn_es_evi *bgp_evpn_es_evi_new(struct bgp_evpn_es *es,
        listnode_init(&es_evi->es_listnode, es_evi);
        listnode_add(es->es_evi_list, &es_evi->es_listnode);
 
+       bgp_evpn_es_vrf_ref(es_evi, vpn->bgp_vrf);
+
        return es_evi;
 }
 
@@ -2169,6 +2876,8 @@ static void bgp_evpn_es_evi_free(struct bgp_evpn_es_evi *es_evi)
        if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL | BGP_EVPNES_EVI_REMOTE))
                return;
 
+       bgp_evpn_es_vrf_deref(es_evi);
+
        /* remove from the ES's VNI list */
        list_delete_node(es->es_evi_list, &es_evi->es_listnode);
 
@@ -2462,13 +3171,30 @@ int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn,
                        vpn->vni, &p->prefix.ead_addr.ip.ipaddr_v4);
 
        es = bgp_evpn_es_find(&p->prefix.ead_addr.esi);
-       if (!es)
-               /* XXX - error logs */
+       if (!es) {
+               if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+                       zlog_debug("del remote %s es %s evi %u vtep %pI4, NO es",
+                                  p->prefix.ead_addr.eth_tag ? "ead-es"
+                                                             : "ead-evi",
+                                  esi_to_str(&p->prefix.ead_addr.esi, buf,
+                                             sizeof(buf)),
+                                  vpn->vni,
+                          &p->prefix.ead_addr.ip.ipaddr_v4);
                return 0;
+       }
        es_evi = bgp_evpn_es_evi_find(es, vpn);
-       if (!es_evi)
-               /* XXX - error logs */
+       if (!es_evi) {
+               if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+                       zlog_debug(
+                               "del remote %s es %s evi %u vtep %pI4, NO es-evi",
+                               p->prefix.ead_addr.eth_tag ? "ead-es"
+                                                          : "ead-evi",
+                               esi_to_str(&p->prefix.ead_addr.esi, buf,
+                                          sizeof(buf)),
+                               vpn->vni,
+                               &p->prefix.ead_addr.ip.ipaddr_v4);
                return 0;
+       }
 
        ead_es = !!p->prefix.ead_addr.eth_tag;
        bgp_evpn_es_evi_vtep_del(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4,
@@ -2556,7 +3282,7 @@ static void bgp_evpn_es_evi_json_vtep_fill(json_object *json_vteps,
                if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES)
                        json_array_string_add(json_flags, "ead-per-es");
                if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_EVI)
-                       json_array_string_add(json_flags, "ed-per-evi");
+                       json_array_string_add(json_flags, "ead-per-evi");
                json_object_object_add(json_vtep_entry,
                                "flags", json_flags);
        }
@@ -2995,6 +3721,8 @@ void bgp_evpn_mh_init(void)
        /* config knobs - XXX add cli to control it */
        bgp_mh_info->ead_evi_adv_for_down_links = true;
        bgp_mh_info->consistency_checking = true;
+       bgp_mh_info->install_l3nhg = false;
+       bgp_mh_info->host_routes_use_l3nhg = BGP_EVPN_MH_USE_ES_L3NHG_DEF;
 
        if (bgp_mh_info->consistency_checking)
                thread_add_timer(bm->master, bgp_evpn_run_consistency_checks,
index d719524bddbc31e88fc8f85a954f24a7ae25ce3f..b6d2a7faaca4a234a8600449f4176d5024063692 100644 (file)
@@ -34,6 +34,7 @@
 
 #define BGP_EVPN_CONS_CHECK_INTERVAL 60
 
+#define BGP_EVPN_MH_USE_ES_L3NHG_DEF true
 
 /* Ethernet Segment entry -
  * - Local and remote ESs are maintained in a global RB tree,
@@ -96,6 +97,14 @@ struct bgp_evpn_es {
        /* List of ES-EVIs associated with this ES */
        struct list *es_evi_list;
 
+       /* List of ES-VRFs associated with this ES */
+       struct list *es_vrf_list;
+
+       /* List of MAC-IP VNI paths using this ES as destination -
+        * element is bgp_path_info_extra->es_info
+        */
+       struct list *macip_path_list;
+
        /* Number of remote VNIs referencing this ES */
        uint32_t remote_es_evi_cnt;
 
@@ -142,6 +151,34 @@ struct bgp_evpn_es_vtep {
        struct listnode es_listnode;
 };
 
+/* ES-VRF element needed for managing L3 NHGs. It is implicitly created
+ * when an ES-EVI is associated with a tenant VRF
+ */
+struct bgp_evpn_es_vrf {
+       struct bgp_evpn_es *es;
+       struct bgp *bgp_vrf;
+
+       uint32_t flags;
+/* NHG can only be activated if there are active VTEPs in the ES and
+ * there is a valid L3-VNI associated with the VRF
+ */
+#define BGP_EVPNES_VRF_NHG_ACTIVE (1 << 0)
+
+       /* memory used for adding the es_vrf to
+        * es_vrf->bgp_vrf->es_vrf_rb_tree
+        */
+       RB_ENTRY(bgp_evpn_es_vrf) rb_node;
+
+       /* memory used for linking the es_vrf to es_vrf->es->es_vrf_list */
+       struct listnode es_listnode;
+
+       uint32_t nhg_id;
+       uint32_t v6_nhg_id;
+
+       /* Number of ES-EVI entries associated with this ES-VRF */
+       uint32_t ref_cnt;
+};
+
 /* ES per-EVI info
  * - ES-EVIs are maintained per-L2-VNI (vpn->es_evi_rb_tree)
  * - ES-EVIs are also linked to the parent ES (es->es_evi_list)
@@ -175,6 +212,8 @@ struct bgp_evpn_es_evi {
 
        /* list of PEs (bgp_evpn_es_evi_vtep) attached to the ES for this VNI */
        struct list *es_evi_vtep_list;
+
+       struct bgp_evpn_es_vrf *es_vrf;
 };
 
 /* PE attached to an ES for a VNI. This entry is created when an EAD-per-ES
@@ -219,6 +258,9 @@ struct bgp_evpn_mh_info {
        bool ead_evi_adv_for_down_links;
        /* Enable ES consistency checking */
        bool consistency_checking;
+       /* Use L3 NHGs for host routes in symmetric IRB */
+       bool install_l3nhg;
+       bool host_routes_use_l3nhg;
 };
 
 /****************************************************************************/
@@ -308,5 +350,19 @@ void bgp_evpn_es_evi_show_vni(struct vty *vty, vni_t vni,
 void bgp_evpn_es_evi_show(struct vty *vty, bool uj, bool detail);
 struct bgp_evpn_es *bgp_evpn_es_find(const esi_t *esi);
 extern bool bgp_evpn_is_esi_local(esi_t *esi);
+extern void bgp_evpn_vrf_es_init(struct bgp *bgp_vrf);
+extern void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi *es_evi);
+extern void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi *es_evi,
+                               struct bgp *bgp_vrf);
+extern void bgp_evpn_path_es_info_free(struct bgp_path_es_info *es_info);
+extern void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info);
+extern void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni,
+                                 esi_t *esi);
+extern bool bgp_evpn_es_is_vtep_active(esi_t *esi, struct in_addr nh);
+extern bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf,
+                                    struct bgp_path_info *pi, uint32_t *nhg_p);
+extern void bgp_evpn_es_vrf_show(struct vty *vty, bool uj,
+                                struct bgp_evpn_es *es);
+extern void bgp_evpn_es_vrf_show_esi(struct vty *vty, esi_t *esi, bool uj);
 
 #endif /* _FRR_BGP_EVPN_MH_H */
index c47576c00c5a768943f1583a73a17241f936b1e1..6a7d12493827839a29fefcb80c1aa7971a67388d 100644 (file)
@@ -218,6 +218,9 @@ static inline struct list *bgpevpn_get_vrf_import_rtl(struct bgpevpn *vpn)
        return vpn->bgp_vrf->vrf_import_rtl;
 }
 
+extern void bgp_evpn_es_evi_vrf_ref(struct bgpevpn *vpn);
+extern void bgp_evpn_es_evi_vrf_deref(struct bgpevpn *vpn);
+
 static inline void bgpevpn_unlink_from_l3vni(struct bgpevpn *vpn)
 {
        /* bail if vpn is not associated to bgp_vrf */
@@ -227,6 +230,8 @@ static inline void bgpevpn_unlink_from_l3vni(struct bgpevpn *vpn)
        UNSET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS);
        listnode_delete(vpn->bgp_vrf->l2vnis, vpn);
 
+       bgp_evpn_es_evi_vrf_deref(vpn);
+
        /* remove the backpointer to the vrf instance */
        bgp_unlock(vpn->bgp_vrf);
        vpn->bgp_vrf = NULL;
@@ -255,6 +260,8 @@ static inline void bgpevpn_link_to_l3vni(struct bgpevpn *vpn)
        if (bgp_vrf->l3vni &&
            !CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY))
                SET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS);
+
+       bgp_evpn_es_evi_vrf_ref(vpn);
 }
 
 static inline int is_vni_configured(struct bgpevpn *vpn)
@@ -508,7 +515,7 @@ static inline void evpn_type1_prefix_global_copy(struct prefix_evpn *global_p,
 {
        memcpy(global_p, vni_p, sizeof(*global_p));
        global_p->prefix.ead_addr.ip.ipa_type = 0;
-       global_p->prefix.ead_addr.ip.ipaddr_v4.s_addr = 0;
+       global_p->prefix.ead_addr.ip.ipaddr_v4.s_addr = INADDR_ANY;
 }
 
 /* EAD prefix in the global table doesn't include the VTEP-IP so
@@ -623,4 +630,13 @@ extern struct bgp_dest *
 bgp_global_evpn_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi,
                            const struct prefix_evpn *evp,
                            struct prefix_rd *prd);
+extern struct bgp_node *bgp_global_evpn_node_get(struct bgp_table *table,
+                                                afi_t afi, safi_t safi,
+                                                const struct prefix_evpn *evp,
+                                                struct prefix_rd *prd);
+extern struct bgp_node *
+bgp_global_evpn_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi,
+                           const struct prefix_evpn *evp,
+                           struct prefix_rd *prd);
+extern void bgp_evpn_import_route_in_vrfs(struct bgp_path_info *pi, int import);
 #endif /* _BGP_EVPN_PRIVATE_H */
index e9e2aafebbec174a26973ef40e55f6306b58e2f5..0f7320562c69c3160541a9bd42163c3b8c784664 100644 (file)
@@ -686,6 +686,78 @@ static void show_esi_routes(struct bgp *bgp,
        }
 }
 
+/* Display all MAC-IP VNI routes linked to an ES */
+static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi,
+                                          json_object *json, int detail)
+{
+       struct bgp_node *rn;
+       struct bgp_path_info *pi;
+       int header = detail ? 0 : 1;
+       uint32_t path_cnt;
+       struct listnode *node;
+       struct bgp_evpn_es *es;
+       struct bgp_path_es_info *es_info;
+       struct bgp *bgp = bgp_get_evpn();
+       json_object *json_paths = NULL;
+
+       if (!bgp)
+               return;
+
+       path_cnt = 0;
+
+       if (json)
+               json_paths = json_object_new_array();
+
+       RB_FOREACH (es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree) {
+
+               if (esi && memcmp(esi, &es->esi, sizeof(*esi)))
+                       continue;
+
+               for (ALL_LIST_ELEMENTS_RO(es->macip_path_list, node, es_info)) {
+                       json_object *json_path = NULL;
+
+                       pi = es_info->pi;
+                       rn = pi->net;
+
+                       if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID))
+                               continue;
+
+                       /* Overall header/legend displayed once. */
+                       if (header) {
+                               bgp_evpn_show_route_header(vty, bgp, 0, json);
+                               header = 0;
+                       }
+
+                       path_cnt++;
+
+                       if (json)
+                               json_path = json_object_new_array();
+
+                       if (detail)
+                               route_vty_out_detail(vty, bgp, rn, pi,
+                                                    AFI_L2VPN, SAFI_EVPN,
+                                                    json_path);
+                       else
+                               route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN,
+                                             json_path, false);
+
+                       if (json)
+                               json_object_array_add(json_paths, json_path);
+               }
+       }
+
+       if (json) {
+               json_object_object_add(json, "paths", json_paths);
+               json_object_int_add(json, "numPaths", path_cnt);
+       } else {
+               if (path_cnt == 0)
+                       vty_out(vty, "There are no MAC-IP ES paths");
+               else
+                       vty_out(vty, "\nDisplayed %u paths\n", path_cnt);
+               vty_out(vty, "\n");
+       }
+}
+
 static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
                            struct vty *vty, struct in_addr vtep_ip,
                            json_object *json, int detail)
@@ -2548,10 +2620,14 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
                if (pi) {
                        /* RD header and legend - once overall. */
                        if (rd_header && !json) {
+                               vty_out(vty,
+                                       "EVPN type-1 prefix: [1]:[ESI]:[EthTag]:[IPlen]:[VTEP-IP]\n");
                                vty_out(vty,
                                        "EVPN type-2 prefix: [2]:[EthTag]:[MAClen]:[MAC]\n");
                                vty_out(vty,
                                        "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
+                               vty_out(vty,
+                                       "EVPN type-4 prefix: [4]:[ESI]:[IPlen]:[OrigIP]\n");
                                vty_out(vty,
                                        "EVPN type-5 prefix: [5]:[EthTag]:[IPlen]:[IP]\n\n");
                                rd_header = 0;
@@ -3675,6 +3751,16 @@ DEFUN (no_bgp_evpn_advertise_type5,
        return CMD_SUCCESS;
 }
 
+DEFPY (bgp_evpn_use_es_l3nhg,
+       bgp_evpn_use_es_l3nhg_cmd,
+       "[no$no] use-es-l3nhg",
+       NO_STR
+       "use L3 nexthop group for host routes with ES destination\n")
+{
+       bgp_mh_info->host_routes_use_l3nhg = no ? false :true;
+       return CMD_SUCCESS;
+}
+
 DEFPY (bgp_evpn_advertise_pip_ip_mac,
        bgp_evpn_advertise_pip_ip_mac_cmd,
        "[no$no] advertise-pip [ip <A.B.C.D> [mac <X:X:X:X:X:X|X:X:X:X:X:X/M>]]",
@@ -3967,6 +4053,28 @@ DEFPY(show_bgp_l2vpn_evpn_es,
        return CMD_SUCCESS;
 }
 
+DEFPY(show_bgp_l2vpn_evpn_es_vrf, show_bgp_l2vpn_evpn_es_vrf_cmd,
+      "show bgp l2vpn evpn es-vrf [NAME$esi_str] [json$uj]",
+      SHOW_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR
+      "Ethernet Segment\n"
+      "ES ID\n" JSON_STR)
+{
+       esi_t esi;
+
+       if (esi_str) {
+               if (!str_to_esi(esi_str, &esi)) {
+                       vty_out(vty, "%%Malformed ESI\n");
+                       return CMD_WARNING;
+               }
+               bgp_evpn_es_vrf_show_esi(vty, &esi, uj);
+       } else {
+
+               bgp_evpn_es_vrf_show(vty, uj, NULL);
+       }
+
+       return CMD_SUCCESS;
+}
+
 /*
  * Display EVPN neighbor summary.
  */
@@ -4517,6 +4625,43 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_all,
        return CMD_SUCCESS;
 }
 
+DEFPY_HIDDEN(
+       show_bgp_l2vpn_evpn_route_mac_ip_es,
+       show_bgp_l2vpn_evpn_route_mac_ip_es_cmd,
+       "show bgp l2vpn evpn route mac-ip-es [NAME$esi_str|detail$detail] [json$uj]",
+       SHOW_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR
+       "EVPN route information\n"
+       "MAC IP routes linked to the ES\n"
+       "ES ID\n"
+       "Detailed information\n" JSON_STR)
+{
+       esi_t esi;
+       esi_t *esi_p;
+       json_object *json = NULL;
+
+       if (esi_str) {
+               if (!str_to_esi(esi_str, &esi)) {
+                       vty_out(vty, "%%Malformed ESI\n");
+                       return CMD_WARNING;
+               }
+               esi_p = &esi;
+       } else {
+               esi_p = NULL;
+       }
+
+       if (uj)
+               json = json_object_new_object();
+       bgp_evpn_show_routes_mac_ip_es(vty, esi_p, json, !!detail);
+       if (uj) {
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+
+       return CMD_SUCCESS;
+}
+
 /*
  * Display EVPN import route-target hash table
  */
@@ -5602,6 +5747,14 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
        if (bgp->evpn_info->advertise_svi_macip)
                vty_out(vty, "  advertise-svi-ip\n");
 
+       if (bgp_mh_info->host_routes_use_l3nhg !=
+                       BGP_EVPN_MH_USE_ES_L3NHG_DEF) {
+               if (bgp_mh_info->host_routes_use_l3nhg)
+                       vty_out(vty, "  use-es-l3nhg\n");
+               else
+                       vty_out(vty, "  no use-es-l3nhg\n");
+       }
+
        if (!bgp->evpn_info->dup_addr_detect)
                vty_out(vty, "  no dup-addr-detection\n");
 
@@ -5746,6 +5899,7 @@ void bgp_ethernetvpn_init(void)
        install_element(BGP_EVPN_NODE, &no_dup_addr_detection_cmd);
        install_element(BGP_EVPN_NODE, &bgp_evpn_flood_control_cmd);
        install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_pip_ip_mac_cmd);
+       install_element(BGP_EVPN_NODE, &bgp_evpn_use_es_l3nhg_cmd);
 
        /* test commands */
        install_element(BGP_EVPN_NODE, &test_es_add_cmd);
@@ -5754,6 +5908,7 @@ void bgp_ethernetvpn_init(void)
        /* "show bgp l2vpn evpn" commands. */
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_es_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_es_evi_cmd);
+       install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_es_vrf_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_summary_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_cmd);
@@ -5765,6 +5920,7 @@ void bgp_ethernetvpn_init(void)
                        &show_bgp_l2vpn_evpn_route_vni_multicast_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_macip_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_all_cmd);
+       install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_mac_ip_es_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vrf_import_rt_cmd);
 
index 55e7973f817ecf54af9092fb5be1053da12c7c94..15b891f25a84b26b9b81bfb9c49df869ca06f4d8 100644 (file)
@@ -229,9 +229,9 @@ int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
        case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
                if (prefix) {
                        if (prefix_local.family == AF_INET)
-                               PREFIX_COPY_IPV4(prefix, &prefix_local)
+                               PREFIX_COPY_IPV4(prefix, &prefix_local);
                        else
-                               PREFIX_COPY_IPV6(prefix, &prefix_local)
+                               PREFIX_COPY_IPV6(prefix, &prefix_local);
                }
                break;
        case BGP_FLOWSPEC_VALIDATE_ONLY:
index 57f212b05dbd4aa15e08241b5e80fd0af1031a45..11487ed8471d4b0f03ca153d9121bdd4785e3a68 100644 (file)
@@ -335,8 +335,8 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p,
                        char local_buff[INET6_ADDRSTRLEN];
 
                        local_buff[0] = '\0';
-                       if (p->u.prefix_flowspec.family == AF_INET &&
-                           attr->nexthop.s_addr != 0)
+                       if (p->u.prefix_flowspec.family == AF_INET
+                           && attr->nexthop.s_addr != INADDR_ANY)
                                inet_ntop(AF_INET,
                                          &attr->nexthop.s_addr,
                                          local_buff,
index dd31a9b7cb36f600dbb468ce42456852c044647c..cec4a9339ab3bce77be406b14e8cc1f6aae86392 100644 (file)
 #include "bgpd/bgp_keepalives.h"
 #include "bgpd/bgp_io.h"
 #include "bgpd/bgp_zebra.h"
+#include "bgpd/bgp_vty.h"
 
 DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer))
 DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer))
-extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
+
 /* Definition of display strings corresponding to FSM events. This should be
  * kept consistent with the events defined in bgpd.h
  */
@@ -67,12 +68,14 @@ static const char *const bgp_event_str[] = {
        "BGP_Start",
        "BGP_Stop",
        "TCP_connection_open",
+       "TCP_connection_open_w_delay",
        "TCP_connection_closed",
        "TCP_connection_open_failed",
        "TCP_fatal_error",
        "ConnectRetry_timer_expired",
        "Hold_Timer_expired",
        "KeepAlive_timer_expired",
+       "DelayOpen_timer_expired",
        "Receive_OPEN_message",
        "Receive_KEEPALIVE_message",
        "Receive_UPDATE_message",
@@ -92,6 +95,7 @@ int bgp_event(struct thread *);
 static int bgp_start_timer(struct thread *);
 static int bgp_connect_timer(struct thread *);
 static int bgp_holdtime_timer(struct thread *);
+static int bgp_delayopen_timer(struct thread *);
 
 /* BGP FSM functions. */
 static int bgp_start(struct peer *);
@@ -174,10 +178,12 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
 
        BGP_TIMER_OFF(peer->t_routeadv);
        BGP_TIMER_OFF(peer->t_connect);
+       BGP_TIMER_OFF(peer->t_delayopen);
        BGP_TIMER_OFF(peer->t_connect_check_r);
        BGP_TIMER_OFF(peer->t_connect_check_w);
        BGP_TIMER_OFF(from_peer->t_routeadv);
        BGP_TIMER_OFF(from_peer->t_connect);
+       BGP_TIMER_OFF(from_peer->t_delayopen);
        BGP_TIMER_OFF(from_peer->t_connect_check_r);
        BGP_TIMER_OFF(from_peer->t_connect_check_w);
        BGP_TIMER_OFF(from_peer->t_process_packet);
@@ -233,6 +239,7 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
        peer->v_holdtime = from_peer->v_holdtime;
        peer->v_keepalive = from_peer->v_keepalive;
        peer->v_routeadv = from_peer->v_routeadv;
+       peer->v_delayopen = from_peer->v_delayopen;
        peer->v_gr_restart = from_peer->v_gr_restart;
        peer->cap = from_peer->cap;
        status = peer->status;
@@ -364,6 +371,7 @@ void bgp_timer_set(struct peer *peer)
                BGP_TIMER_OFF(peer->t_holdtime);
                bgp_keepalives_off(peer);
                BGP_TIMER_OFF(peer->t_routeadv);
+               BGP_TIMER_OFF(peer->t_delayopen);
                break;
 
        case Connect:
@@ -371,8 +379,13 @@ void bgp_timer_set(struct peer *peer)
                   status.  Make sure start timer is off and connect timer is
                   on. */
                BGP_TIMER_OFF(peer->t_start);
-               BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
-                            peer->v_connect);
+               if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN))
+                       BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
+                                    (peer->v_delayopen + peer->v_connect));
+               else
+                       BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
+                                    peer->v_connect);
+
                BGP_TIMER_OFF(peer->t_holdtime);
                bgp_keepalives_off(peer);
                BGP_TIMER_OFF(peer->t_routeadv);
@@ -387,8 +400,13 @@ void bgp_timer_set(struct peer *peer)
                    || CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) {
                        BGP_TIMER_OFF(peer->t_connect);
                } else {
-                       BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
-                                    peer->v_connect);
+                       if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN))
+                               BGP_TIMER_ON(
+                                       peer->t_connect, bgp_connect_timer,
+                                       (peer->v_delayopen + peer->v_connect));
+                       else
+                               BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
+                                            peer->v_connect);
                }
                BGP_TIMER_OFF(peer->t_holdtime);
                bgp_keepalives_off(peer);
@@ -407,6 +425,7 @@ void bgp_timer_set(struct peer *peer)
                }
                bgp_keepalives_off(peer);
                BGP_TIMER_OFF(peer->t_routeadv);
+               BGP_TIMER_OFF(peer->t_delayopen);
                break;
 
        case OpenConfirm:
@@ -425,6 +444,7 @@ void bgp_timer_set(struct peer *peer)
                        bgp_keepalives_on(peer);
                }
                BGP_TIMER_OFF(peer->t_routeadv);
+               BGP_TIMER_OFF(peer->t_delayopen);
                break;
 
        case Established:
@@ -432,6 +452,7 @@ void bgp_timer_set(struct peer *peer)
                   off. */
                BGP_TIMER_OFF(peer->t_start);
                BGP_TIMER_OFF(peer->t_connect);
+               BGP_TIMER_OFF(peer->t_delayopen);
 
                /* Same as OpenConfirm, if holdtime is zero then both holdtime
                   and keepalive must be turned off. */
@@ -448,6 +469,7 @@ void bgp_timer_set(struct peer *peer)
                BGP_TIMER_OFF(peer->t_gr_restart);
                BGP_TIMER_OFF(peer->t_gr_stale);
                BGP_TIMER_OFF(peer->t_pmax_restart);
+               BGP_TIMER_OFF(peer->t_refresh_stalepath);
        /* fallthru */
        case Clearing:
                BGP_TIMER_OFF(peer->t_start);
@@ -455,6 +477,7 @@ void bgp_timer_set(struct peer *peer)
                BGP_TIMER_OFF(peer->t_holdtime);
                bgp_keepalives_off(peer);
                BGP_TIMER_OFF(peer->t_routeadv);
+               BGP_TIMER_OFF(peer->t_delayopen);
                break;
        case BGP_STATUS_MAX:
                flog_err(EC_LIB_DEVELOPMENT,
@@ -488,6 +511,10 @@ static int bgp_connect_timer(struct thread *thread)
 
        peer = THREAD_ARG(thread);
 
+       /* stop the DelayOpenTimer if it is running */
+       if (peer->t_delayopen)
+               BGP_TIMER_OFF(peer->t_delayopen);
+
        assert(!peer->t_write);
        assert(!peer->t_read);
 
@@ -564,6 +591,23 @@ int bgp_routeadv_timer(struct thread *thread)
        return 0;
 }
 
+/* RFC 4271 DelayOpenTimer */
+int bgp_delayopen_timer(struct thread *thread)
+{
+       struct peer *peer;
+
+       peer = THREAD_ARG(thread);
+
+       if (bgp_debug_neighbor_events(peer))
+               zlog_debug("%s [FSM] Timer (DelayOpentimer expire)",
+                          peer->host);
+
+       THREAD_VAL(thread) = DelayOpen_timer_expired;
+       bgp_event(thread); /* bgp_event unlocks peer */
+
+       return 0;
+}
+
 /* BGP Peer Down Cause */
 const char *const peer_down_str[] = {"",
                               "Router ID changed",
@@ -1240,6 +1284,16 @@ int bgp_stop(struct peer *peer)
                                        peer->nsf[afi][safi] = 0;
                }
 
+               /* Stop route-refresh stalepath timer */
+               if (peer->t_refresh_stalepath) {
+                       BGP_TIMER_OFF(peer->t_refresh_stalepath);
+
+                       if (bgp_debug_neighbor_events(peer))
+                               zlog_debug(
+                                       "%s: route-refresh restart stalepath timer stopped",
+                                       peer->host);
+               }
+
                /* If peer reset before receiving EOR, decrement EOR count and
                 * cancel the selection deferral timer if there are no
                 * pending EOR messages to be received
@@ -1299,6 +1353,7 @@ int bgp_stop(struct peer *peer)
        BGP_TIMER_OFF(peer->t_connect);
        BGP_TIMER_OFF(peer->t_holdtime);
        BGP_TIMER_OFF(peer->t_routeadv);
+       BGP_TIMER_OFF(peer->t_delayopen);
 
        /* Clear input and output buffer.  */
        frr_with_mutex(&peer->io_mtx) {
@@ -1357,6 +1412,12 @@ int bgp_stop(struct peer *peer)
                peer->v_holdtime = peer->bgp->default_holdtime;
        }
 
+       /* Reset DelayOpenTime */
+       if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN))
+               peer->v_delayopen = peer->delayopen;
+       else
+               peer->v_delayopen = peer->bgp->default_delayopen;
+
        peer->update_time = 0;
 
 /* Until we are sure that there is no problem about prefix count
@@ -1469,7 +1530,10 @@ static int bgp_connect_check(struct thread *thread)
 
        /* When status is 0 then TCP connection is established. */
        if (status == 0) {
-               BGP_EVENT_ADD(peer, TCP_connection_open);
+               if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN))
+                       BGP_EVENT_ADD(peer, TCP_connection_open_w_delay);
+               else
+                       BGP_EVENT_ADD(peer, TCP_connection_open);
                return 1;
        } else {
                if (bgp_debug_neighbor_events(peer))
@@ -1516,11 +1580,63 @@ static int bgp_connect_success(struct peer *peer)
                        zlog_debug("%s passive open", peer->host);
        }
 
+       /* Send an open message */
        bgp_open_send(peer);
 
        return 0;
 }
 
+/* TCP connection open with RFC 4271 optional session attribute DelayOpen flag
+ * set.
+ */
+static int bgp_connect_success_w_delayopen(struct peer *peer)
+{
+       if (peer->fd < 0) {
+               flog_err(EC_BGP_CONNECT, "%s: peer's fd is negative value %d",
+                        __func__, peer->fd);
+               bgp_stop(peer);
+               return -1;
+       }
+
+       if (bgp_getsockname(peer) < 0) {
+               flog_err_sys(EC_LIB_SOCKET,
+                            "%s: bgp_getsockname(): failed for peer %s, fd %d",
+                            __func__, peer->host, peer->fd);
+               bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR,
+                               bgp_fsm_error_subcode(peer->status));
+               bgp_writes_on(peer);
+               return -1;
+       }
+
+       bgp_reads_on(peer);
+
+       if (bgp_debug_neighbor_events(peer)) {
+               char buf1[SU_ADDRSTRLEN];
+
+               if (!CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER))
+                       zlog_debug("%s open active, local address %s",
+                                  peer->host,
+                                  sockunion2str(peer->su_local, buf1,
+                                                SU_ADDRSTRLEN));
+               else
+                       zlog_debug("%s passive open", peer->host);
+       }
+
+       /* set the DelayOpenTime to the inital value */
+       peer->v_delayopen = peer->delayopen;
+
+       /* Start the DelayOpenTimer if it is not already running */
+       if (!peer->t_delayopen)
+               BGP_TIMER_ON(peer->t_delayopen, bgp_delayopen_timer,
+                            peer->v_delayopen);
+
+       if (bgp_debug_neighbor_events(peer))
+               zlog_debug("%s [FSM] BGP OPEN message delayed for %d seconds",
+                          peer->host, peer->delayopen);
+
+       return 0;
+}
+
 /* TCP connect fail */
 static int bgp_connect_fail(struct peer *peer)
 {
@@ -1535,7 +1651,8 @@ static int bgp_connect_fail(struct peer *peer)
 }
 
 /* This function is the first starting point of all BGP connection. It
-   try to connect to remote peer with non-blocking IO. */
+ * try to connect to remote peer with non-blocking IO.
+ */
 int bgp_start(struct peer *peer)
 {
        int status;
@@ -1633,6 +1750,7 @@ int bgp_start(struct peer *peer)
                        zlog_debug(
                                "%s [FSM] Connect immediately success, fd %d",
                                peer->host, peer->fd);
+
                BGP_EVENT_ADD(peer, TCP_connection_open);
                break;
        case connect_in_progress:
@@ -1682,6 +1800,10 @@ static int bgp_reconnect(struct peer *peer)
 
 static int bgp_fsm_open(struct peer *peer)
 {
+       /* If DelayOpen is active, we may still need to send an open message */
+       if ((peer->status == Connect) || (peer->status == Active))
+               bgp_open_send(peer);
+
        /* Send keepalive and make keepalive timer */
        bgp_keepalive_send(peer);
 
@@ -1709,6 +1831,21 @@ static int bgp_fsm_holdtime_expire(struct peer *peer)
        return bgp_stop_with_notify(peer, BGP_NOTIFY_HOLD_ERR, 0);
 }
 
+/* RFC 4271 DelayOpenTimer_Expires event */
+static int bgp_fsm_delayopen_timer_expire(struct peer *peer)
+{
+       /* Stop the DelayOpenTimer */
+       BGP_TIMER_OFF(peer->t_delayopen);
+
+       /* Send open message to peer */
+       bgp_open_send(peer);
+
+       /* Set the HoldTimer to a large value (4 minutes) */
+       peer->v_holdtime = 245;
+
+       return 0;
+}
+
 /* Start the selection deferral timer thread for the specified AFI, SAFI */
 static int bgp_start_deferral_timer(struct bgp *bgp, afi_t afi, safi_t safi,
                                    struct graceful_restart_info *gr_info)
@@ -1940,14 +2077,16 @@ static int bgp_establish(struct peer *peer)
                               PEER_CAP_ORF_PREFIX_SM_ADV)) {
                        if (CHECK_FLAG(peer->af_cap[afi][safi],
                                       PEER_CAP_ORF_PREFIX_RM_RCV))
-                               bgp_route_refresh_send(peer, afi, safi,
-                                                      ORF_TYPE_PREFIX,
-                                                      REFRESH_IMMEDIATE, 0);
+                               bgp_route_refresh_send(
+                                       peer, afi, safi, ORF_TYPE_PREFIX,
+                                       REFRESH_IMMEDIATE, 0,
+                                       BGP_ROUTE_REFRESH_NORMAL);
                        else if (CHECK_FLAG(peer->af_cap[afi][safi],
                                            PEER_CAP_ORF_PREFIX_RM_OLD_RCV))
-                               bgp_route_refresh_send(peer, afi, safi,
-                                                      ORF_TYPE_PREFIX_OLD,
-                                                      REFRESH_IMMEDIATE, 0);
+                               bgp_route_refresh_send(
+                                       peer, afi, safi, ORF_TYPE_PREFIX_OLD,
+                                       REFRESH_IMMEDIATE, 0,
+                                       BGP_ROUTE_REFRESH_NORMAL);
                }
        }
 
@@ -2089,12 +2228,14 @@ static const struct {
                {bgp_start, Connect}, /* BGP_Start                    */
                {bgp_stop, Idle},     /* BGP_Stop                     */
                {bgp_stop, Idle},     /* TCP_connection_open          */
+               {bgp_stop, Idle},     /* TCP_connection_open_w_delay */
                {bgp_stop, Idle},     /* TCP_connection_closed        */
                {bgp_ignore, Idle},   /* TCP_connection_open_failed   */
                {bgp_stop, Idle},     /* TCP_fatal_error              */
                {bgp_ignore, Idle},   /* ConnectRetry_timer_expired   */
                {bgp_ignore, Idle},   /* Hold_Timer_expired           */
                {bgp_ignore, Idle},   /* KeepAlive_timer_expired      */
+               {bgp_ignore, Idle},   /* DelayOpen_timer_expired */
                {bgp_ignore, Idle},   /* Receive_OPEN_message         */
                {bgp_ignore, Idle},   /* Receive_KEEPALIVE_message    */
                {bgp_ignore, Idle},   /* Receive_UPDATE_message       */
@@ -2106,46 +2247,56 @@ static const struct {
                {bgp_ignore, Connect}, /* BGP_Start                    */
                {bgp_stop, Idle},      /* BGP_Stop                     */
                {bgp_connect_success, OpenSent}, /* TCP_connection_open */
+               {bgp_connect_success_w_delayopen,
+                Connect},                  /* TCP_connection_open_w_delay */
                {bgp_stop, Idle},          /* TCP_connection_closed        */
                {bgp_connect_fail, Active}, /* TCP_connection_open_failed   */
                {bgp_connect_fail, Idle},   /* TCP_fatal_error              */
                {bgp_reconnect, Connect},   /* ConnectRetry_timer_expired   */
                {bgp_fsm_exeption, Idle},   /* Hold_Timer_expired           */
                {bgp_fsm_exeption, Idle},   /* KeepAlive_timer_expired      */
-               {bgp_fsm_exeption, Idle},   /* Receive_OPEN_message         */
-               {bgp_fsm_exeption, Idle},   /* Receive_KEEPALIVE_message    */
-               {bgp_fsm_exeption, Idle},   /* Receive_UPDATE_message       */
-               {bgp_stop, Idle},          /* Receive_NOTIFICATION_message */
-               {bgp_fsm_exeption, Idle},   /* Clearing_Completed           */
+               {bgp_fsm_delayopen_timer_expire,
+                OpenSent},                  /* DelayOpen_timer_expired */
+               {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message         */
+               {bgp_fsm_exeption, Idle},    /* Receive_KEEPALIVE_message    */
+               {bgp_fsm_exeption, Idle},    /* Receive_UPDATE_message       */
+               {bgp_stop, Idle},           /* Receive_NOTIFICATION_message */
+               {bgp_fsm_exeption, Idle},    /* Clearing_Completed           */
        },
        {
                /* Active, */
                {bgp_ignore, Active}, /* BGP_Start                    */
                {bgp_stop, Idle},     /* BGP_Stop                     */
                {bgp_connect_success, OpenSent}, /* TCP_connection_open */
+               {bgp_connect_success_w_delayopen,
+                Active},                 /* TCP_connection_open_w_delay */
                {bgp_stop, Idle},        /* TCP_connection_closed        */
                {bgp_ignore, Active},     /* TCP_connection_open_failed   */
                {bgp_fsm_exeption, Idle}, /* TCP_fatal_error              */
                {bgp_start, Connect},     /* ConnectRetry_timer_expired   */
                {bgp_fsm_exeption, Idle}, /* Hold_Timer_expired           */
                {bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired      */
-               {bgp_fsm_exeption, Idle}, /* Receive_OPEN_message         */
-               {bgp_fsm_exeption, Idle}, /* Receive_KEEPALIVE_message    */
-               {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message       */
-               {bgp_fsm_exeption, Idle}, /* Receive_NOTIFICATION_message */
-               {bgp_fsm_exeption, Idle}, /* Clearing_Completed           */
+               {bgp_fsm_delayopen_timer_expire,
+                OpenSent},                  /* DelayOpen_timer_expired */
+               {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message         */
+               {bgp_fsm_exeption, Idle},    /* Receive_KEEPALIVE_message    */
+               {bgp_fsm_exeption, Idle},    /* Receive_UPDATE_message       */
+               {bgp_fsm_exeption, Idle},    /* Receive_NOTIFICATION_message */
+               {bgp_fsm_exeption, Idle},    /* Clearing_Completed           */
        },
        {
                /* OpenSent, */
                {bgp_ignore, OpenSent},   /* BGP_Start                    */
                {bgp_stop, Idle},        /* BGP_Stop                     */
                {bgp_stop, Active},       /* TCP_connection_open          */
+               {bgp_fsm_exeption, Idle}, /* TCP_connection_open_w_delay */
                {bgp_stop, Active},       /* TCP_connection_closed        */
                {bgp_stop, Active},       /* TCP_connection_open_failed   */
                {bgp_stop, Active},       /* TCP_fatal_error              */
                {bgp_fsm_exeption, Idle}, /* ConnectRetry_timer_expired   */
                {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
                {bgp_fsm_exeption, Idle},    /* KeepAlive_timer_expired      */
+               {bgp_fsm_exeption, Idle},    /* DelayOpen_timer_expired */
                {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message         */
                {bgp_fsm_event_error, Idle}, /* Receive_KEEPALIVE_message    */
                {bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message       */
@@ -2157,12 +2308,14 @@ static const struct {
                {bgp_ignore, OpenConfirm}, /* BGP_Start                    */
                {bgp_stop, Idle},         /* BGP_Stop                     */
                {bgp_stop, Idle},         /* TCP_connection_open          */
+               {bgp_fsm_exeption, Idle},  /* TCP_connection_open_w_delay */
                {bgp_stop, Idle},         /* TCP_connection_closed        */
                {bgp_stop, Idle},         /* TCP_connection_open_failed   */
                {bgp_stop, Idle},         /* TCP_fatal_error              */
                {bgp_fsm_exeption, Idle},  /* ConnectRetry_timer_expired   */
                {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
                {bgp_ignore, OpenConfirm},    /* KeepAlive_timer_expired      */
+               {bgp_fsm_exeption, Idle},     /* DelayOpen_timer_expired */
                {bgp_fsm_exeption, Idle},     /* Receive_OPEN_message         */
                {bgp_establish, Established}, /* Receive_KEEPALIVE_message    */
                {bgp_fsm_exeption, Idle},     /* Receive_UPDATE_message       */
@@ -2174,12 +2327,14 @@ static const struct {
                {bgp_ignore, Established}, /* BGP_Start                    */
                {bgp_stop, Clearing},      /* BGP_Stop                     */
                {bgp_stop, Clearing},      /* TCP_connection_open          */
+               {bgp_fsm_exeption, Idle},  /* TCP_connection_open_w_delay */
                {bgp_stop, Clearing},      /* TCP_connection_closed        */
                {bgp_stop, Clearing},      /* TCP_connection_open_failed   */
                {bgp_stop, Clearing},      /* TCP_fatal_error              */
                {bgp_stop, Clearing},      /* ConnectRetry_timer_expired   */
                {bgp_fsm_holdtime_expire, Clearing}, /* Hold_Timer_expired */
                {bgp_ignore, Established}, /* KeepAlive_timer_expired      */
+               {bgp_fsm_exeption, Idle},  /* DelayOpen_timer_expired */
                {bgp_stop, Clearing},      /* Receive_OPEN_message         */
                {bgp_fsm_keepalive,
                 Established}, /* Receive_KEEPALIVE_message    */
@@ -2193,12 +2348,14 @@ static const struct {
                {bgp_ignore, Clearing}, /* BGP_Start                    */
                {bgp_stop, Clearing},   /* BGP_Stop                     */
                {bgp_stop, Clearing},   /* TCP_connection_open          */
+               {bgp_stop, Clearing},   /* TCP_connection_open_w_delay */
                {bgp_stop, Clearing},   /* TCP_connection_closed        */
                {bgp_stop, Clearing},   /* TCP_connection_open_failed   */
                {bgp_stop, Clearing},   /* TCP_fatal_error              */
                {bgp_stop, Clearing},   /* ConnectRetry_timer_expired   */
                {bgp_stop, Clearing},   /* Hold_Timer_expired           */
                {bgp_stop, Clearing},   /* KeepAlive_timer_expired      */
+               {bgp_stop, Clearing},   /* DelayOpen_timer_expired */
                {bgp_stop, Clearing},   /* Receive_OPEN_message         */
                {bgp_stop, Clearing},   /* Receive_KEEPALIVE_message    */
                {bgp_stop, Clearing},   /* Receive_UPDATE_message       */
@@ -2210,12 +2367,14 @@ static const struct {
                {bgp_ignore, Deleted}, /* BGP_Start                    */
                {bgp_ignore, Deleted}, /* BGP_Stop                     */
                {bgp_ignore, Deleted}, /* TCP_connection_open          */
+               {bgp_ignore, Deleted}, /* TCP_connection_open_w_delay */
                {bgp_ignore, Deleted}, /* TCP_connection_closed        */
                {bgp_ignore, Deleted}, /* TCP_connection_open_failed   */
                {bgp_ignore, Deleted}, /* TCP_fatal_error              */
                {bgp_ignore, Deleted}, /* ConnectRetry_timer_expired   */
                {bgp_ignore, Deleted}, /* Hold_Timer_expired           */
                {bgp_ignore, Deleted}, /* KeepAlive_timer_expired      */
+               {bgp_ignore, Deleted}, /* DelayOpen_timer_expired */
                {bgp_ignore, Deleted}, /* Receive_OPEN_message         */
                {bgp_ignore, Deleted}, /* Receive_KEEPALIVE_message    */
                {bgp_ignore, Deleted}, /* Receive_UPDATE_message       */
index 4f440cd1f822f8ef9cb6929052f190d337e90fe5..5a31bd0243ee9298f3a449a24530f1d24a4be07f 100644 (file)
@@ -120,6 +120,65 @@ mpls_label_t bgp_adv_label(struct bgp_dest *dest, struct bgp_path_info *pi,
        return dest->local_label;
 }
 
+static void bgp_send_fec_register_label_msg(struct bgp_dest *dest, bool reg,
+                                           uint32_t label_index)
+{
+       struct stream *s;
+       int command;
+       const struct prefix *p;
+       uint16_t flags = 0;
+       size_t flags_pos = 0;
+       mpls_label_t *local_label = &(dest->local_label);
+       bool have_label_to_reg =
+               bgp_is_valid_label(local_label)
+               && label_pton(local_label) != MPLS_LABEL_IMPLICIT_NULL;
+
+       p = bgp_dest_get_prefix(dest);
+
+       /* Check socket. */
+       if (!zclient || zclient->sock < 0)
+               return;
+
+       if (BGP_DEBUG(labelpool, LABELPOOL))
+               zlog_debug("%s: FEC %sregister %pRN label_index=%u label=%u",
+                          __func__, reg ? "" : "un", bgp_dest_to_rnode(dest),
+                          label_index, label_pton(local_label));
+       /* If the route node has a local_label assigned or the
+        * path node has an MPLS SR label index allowing zebra to
+        * derive the label, proceed with registration. */
+       s = zclient->obuf;
+       stream_reset(s);
+       command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER;
+       zclient_create_header(s, command, VRF_DEFAULT);
+       flags_pos = stream_get_endp(s); /* save position of 'flags' */
+       stream_putw(s, flags);          /* initial flags */
+       stream_putw(s, PREFIX_FAMILY(p));
+       stream_put_prefix(s, p);
+       if (reg) {
+               /* label index takes precedence over auto-assigned label. */
+               if (label_index != 0) {
+                       flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX;
+                       stream_putl(s, label_index);
+               } else if (have_label_to_reg) {
+                       flags |= ZEBRA_FEC_REGISTER_LABEL;
+                       stream_putl(s, label_pton(local_label));
+               }
+               SET_FLAG(dest->flags, BGP_NODE_REGISTERED_FOR_LABEL);
+       } else
+               UNSET_FLAG(dest->flags, BGP_NODE_REGISTERED_FOR_LABEL);
+
+       /* Set length and flags */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       /*
+        * We only need to write new flags if this is a register
+        */
+       if (reg)
+               stream_putw_at(s, flags_pos, flags);
+
+       zclient_send_message(zclient);
+}
+
 /**
  * This is passed as the callback function to bgp_labelpool.c:bgp_lp_get()
  * by bgp_reg_dereg_for_label() when a label needs to be obtained from
@@ -130,20 +189,21 @@ mpls_label_t bgp_adv_label(struct bgp_dest *dest, struct bgp_path_info *pi,
 int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
                               bool allocated)
 {
-       struct bgp_path_info *pi;
        struct bgp_dest *dest;
 
-       pi = labelid;
-       /* Is this path still valid? */
-       if (!bgp_path_info_unlock(pi)) {
-               if (BGP_DEBUG(labelpool, LABELPOOL))
-                       zlog_debug(
-                               "%s: bgp_path_info is no longer valid, ignoring",
-                               __func__);
+       dest = labelid;
+
+       /*
+        * if the route had been removed or the request has gone then reject
+        * the allocated label. The requesting code will have done what is
+        * required to allocate the correct label
+        */
+       if (!CHECK_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED)) {
+               bgp_dest_unlock_node(dest);
                return -1;
        }
 
-       dest = pi->net;
+       bgp_dest_unlock_node(dest);
 
        if (BGP_DEBUG(labelpool, LABELPOOL))
                zlog_debug("%s: FEC %pRN label=%u, allocated=%d", __func__,
@@ -151,47 +211,15 @@ int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
 
        if (!allocated) {
                /*
-                * previously-allocated label is now invalid
+                * previously-allocated label is now invalid, set to implicit
+                * null until new label arrives
                 */
-               if (pi->attr->label_index == MPLS_INVALID_LABEL_INDEX
-                   && pi->attr->label != MPLS_LABEL_NONE
-                   && CHECK_FLAG(dest->flags, BGP_NODE_REGISTERED_FOR_LABEL)) {
-                       bgp_unregister_for_label(dest);
+               if (CHECK_FLAG(dest->flags, BGP_NODE_REGISTERED_FOR_LABEL)) {
+                       UNSET_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED);
                        label_ntop(MPLS_LABEL_IMPLICIT_NULL, 1,
                                   &dest->local_label);
                        bgp_set_valid_label(&dest->local_label);
                }
-               return 0;
-       }
-
-       /*
-        * label index is assigned, this should be handled by SR-related code,
-        * so retry FEC registration and then reject label allocation for
-        * it to be released to label pool
-        */
-       if (pi->attr->label_index != MPLS_INVALID_LABEL_INDEX) {
-               flog_err(
-                       EC_BGP_LABEL,
-                       "%s: FEC %pRN Rejecting allocated label %u as Label Index is %u",
-                       __func__, bgp_dest_to_rnode(dest), new_label,
-                       pi->attr->label_index);
-
-               bgp_register_for_label(pi->net, pi);
-
-               return -1;
-       }
-
-       if (pi->attr->label != MPLS_INVALID_LABEL) {
-               if (new_label == pi->attr->label) {
-                       /* already have same label, accept but do nothing */
-                       return 0;
-               }
-               /* Shouldn't happen: different label allocation */
-               flog_err(EC_BGP_LABEL,
-                        "%s: %pRN had label %u but got new assignment %u",
-                        __func__, bgp_dest_to_rnode(dest), pi->attr->label,
-                        new_label);
-               /* continue means use new one */
        }
 
        label_ntop(new_label, 1, &dest->local_label);
@@ -200,7 +228,7 @@ int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
        /*
         * Get back to registering the FEC
         */
-       bgp_register_for_label(pi->net, pi);
+       bgp_send_fec_register_label_msg(dest, true, 0);
 
        return 0;
 }
@@ -209,20 +237,12 @@ void bgp_reg_dereg_for_label(struct bgp_dest *dest, struct bgp_path_info *pi,
                             bool reg)
 {
        bool with_label_index = false;
-       struct stream *s;
        const struct prefix *p;
-       mpls_label_t *local_label;
-       int command;
-       uint16_t flags = 0;
-       size_t flags_pos = 0;
+       bool have_label_to_reg =
+               bgp_is_valid_label(&dest->local_label)
+               && label_pton(&dest->local_label) != MPLS_LABEL_IMPLICIT_NULL;
 
        p = bgp_dest_get_prefix(dest);
-       local_label = &(dest->local_label);
-       /* this prevents the loop when we're called by
-        * bgp_reg_for_label_callback()
-        */
-       bool have_label_to_reg = bgp_is_valid_label(local_label)
-                       && label_pton(local_label) != MPLS_LABEL_IMPLICIT_NULL;
 
        if (reg) {
                assert(pi);
@@ -234,67 +254,37 @@ void bgp_reg_dereg_for_label(struct bgp_dest *dest, struct bgp_path_info *pi,
                            ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID))
                        && pi->attr->label_index != BGP_INVALID_LABEL_INDEX) {
                        with_label_index = true;
+                       UNSET_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED);
                } else {
                        /*
-                        * If no label index was provided -- assume any label
+                        * If no label has been registered -- assume any label
                         * from label pool will do. This means that label index
                         * always takes precedence over auto-assigned labels.
                         */
                        if (!have_label_to_reg) {
+                               SET_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED);
                                if (BGP_DEBUG(labelpool, LABELPOOL))
                                        zlog_debug(
                                                "%s: Requesting label from LP for %pFX",
                                                __func__, p);
-
-                               /* bgp_reg_for_label_callback() will call back
-                                * __func__ when it gets a label from the pool.
-                                * This means we'll never register FECs without
-                                * valid labels.
+                               /* bgp_reg_for_label_callback() will deal with
+                                * fec registration when it gets a label from
+                                * the pool. This means we'll never register
+                                * FECs withoutvalid labels.
                                 */
-                               bgp_lp_get(LP_TYPE_BGP_LU, pi,
-                                   bgp_reg_for_label_callback);
+                               bgp_lp_get(LP_TYPE_BGP_LU, dest,
+                                          bgp_reg_for_label_callback);
                                return;
                        }
                }
+       } else {
+               UNSET_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED);
+               bgp_lp_release(LP_TYPE_BGP_LU, dest,
+                              label_pton(&dest->local_label));
        }
 
-       /* Check socket. */
-       if (!zclient || zclient->sock < 0)
-               return;
-
-       /* If the route node has a local_label assigned or the
-        * path node has an MPLS SR label index allowing zebra to
-        * derive the label, proceed with registration. */
-       s = zclient->obuf;
-       stream_reset(s);
-       command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER;
-       zclient_create_header(s, command, VRF_DEFAULT);
-       flags_pos = stream_get_endp(s); /* save position of 'flags' */
-       stream_putw(s, flags);          /* initial flags */
-       stream_putw(s, PREFIX_FAMILY(p));
-       stream_put_prefix(s, p);
-       if (reg) {
-               if (have_label_to_reg) {
-                       flags |= ZEBRA_FEC_REGISTER_LABEL;
-                       stream_putl(s, label_pton(local_label));
-               } else if (with_label_index) {
-                       flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX;
-                       stream_putl(s, pi->attr->label_index);
-               }
-               SET_FLAG(dest->flags, BGP_NODE_REGISTERED_FOR_LABEL);
-       } else
-               UNSET_FLAG(dest->flags, BGP_NODE_REGISTERED_FOR_LABEL);
-
-       /* Set length and flags */
-       stream_putw_at(s, 0, stream_get_endp(s));
-
-       /*
-        * We only need to write new flags if this is a register
-        */
-       if (reg)
-               stream_putw_at(s, flags_pos, flags);
-
-       zclient_send_message(zclient);
+       bgp_send_fec_register_label_msg(
+               dest, reg, with_label_index ? pi->attr->label_index : 0);
 }
 
 static int bgp_nlri_get_labels(struct peer *peer, uint8_t *pnt, uint8_t plen,
index feda0328bd5af13228421d60914f716df65f9d71..001340be3506b8b06ffbeb9ca18977bb023bdfb1 100644 (file)
@@ -182,18 +182,18 @@ void bgp_lp_init(struct thread_master *master, struct labelpool *pool)
        lp->callback_q->spec.max_retries = 0;
 }
 
-/* check if a label callback was for a BGP LU path, and if so, unlock it */
+/* check if a label callback was for a BGP LU node, and if so, unlock it */
 static void check_bgp_lu_cb_unlock(struct lp_lcb *lcb)
 {
        if (lcb->type == LP_TYPE_BGP_LU)
-               bgp_path_info_unlock(lcb->labelid);
+               bgp_dest_unlock_node(lcb->labelid);
 }
 
-/* check if a label callback was for a BGP LU path, and if so, lock it */
+/* check if a label callback was for a BGP LU node, and if so, lock it */
 static void check_bgp_lu_cb_lock(struct lp_lcb *lcb)
 {
        if (lcb->type == LP_TYPE_BGP_LU)
-               bgp_path_info_lock(lcb->labelid);
+               bgp_dest_lock_node(lcb->labelid);
 }
 
 void bgp_lp_finish(void)
@@ -356,7 +356,7 @@ void bgp_lp_get(
                q->labelid = lcb->labelid;
                q->allocated = true;
 
-               /* if this is a LU request, lock path info before queueing */
+               /* if this is a LU request, lock node before queueing */
                check_bgp_lu_cb_lock(lcb);
 
                work_queue_add(lp->callback_q, q);
@@ -384,7 +384,7 @@ void bgp_lp_get(
                sizeof(struct lp_fifo));
 
        lf->lcb = *lcb;
-       /* if this is a LU request, lock path info before queueing */
+       /* if this is a LU request, lock node before queueing */
        check_bgp_lu_cb_lock(lcb);
 
        lp_fifo_add_tail(&lp->requests, lf);
@@ -392,8 +392,9 @@ void bgp_lp_get(
        if (lp_fifo_count(&lp->requests) > lp->pending_count) {
                if (!zclient || zclient->sock < 0)
                        return;
-               if (!zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE,
-                                                 MPLS_LABEL_BASE_ANY))
+               if (zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE,
+                                                MPLS_LABEL_BASE_ANY)
+                   != ZCLIENT_SEND_FAILURE)
                        lp->pending_count += LP_CHUNK_SIZE;
        }
 }
@@ -460,6 +461,9 @@ void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last)
                                zlog_debug("%s: labelid %p: request no longer in effect",
                                                __func__, labelid);
                        }
+                       /* if this was a BGP_LU request, unlock node
+                        */
+                       check_bgp_lu_cb_unlock(lcb);
                        goto finishedrequest;
                }
 
@@ -471,7 +475,7 @@ void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last)
                                                __func__, labelid,
                                                lcb->label, lcb->label, lcb);
                        }
-                       /* if this was a BGP_LU request, unlock path info node
+                       /* if this was a BGP_LU request, unlock node
                         */
                        check_bgp_lu_cb_unlock(lcb);
 
@@ -537,6 +541,7 @@ void bgp_lp_event_zebra_up(void)
        struct lp_lcb *lcb;
        int lm_init_ok;
 
+       lp->reconnect_count++;
        /*
         * Get label chunk allocation request dispatched to zebra
         */
@@ -606,3 +611,371 @@ void bgp_lp_event_zebra_up(void)
                skiplist_delete_first(lp->inuse);
        }
 }
+
+DEFUN(show_bgp_labelpool_summary, show_bgp_labelpool_summary_cmd,
+      "show bgp labelpool summary [json]",
+      SHOW_STR BGP_STR
+      "BGP Labelpool information\n"
+      "BGP Labelpool summary\n" JSON_STR)
+{
+       bool uj = use_json(argc, argv);
+       json_object *json = NULL;
+
+       if (!lp) {
+               if (uj)
+                       vty_out(vty, "{}\n");
+               else
+                       vty_out(vty, "No existing BGP labelpool\n");
+               return (CMD_WARNING);
+       }
+
+       if (uj) {
+               json = json_object_new_object();
+               json_object_int_add(json, "Ledger", skiplist_count(lp->ledger));
+               json_object_int_add(json, "InUse", skiplist_count(lp->inuse));
+               json_object_int_add(json, "Requests",
+                                   lp_fifo_count(&lp->requests));
+               json_object_int_add(json, "LabelChunks", listcount(lp->chunks));
+               json_object_int_add(json, "Pending", lp->pending_count);
+               json_object_int_add(json, "Reconnects", lp->reconnect_count);
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       } else {
+               vty_out(vty, "Labelpool Summary\n");
+               vty_out(vty, "-----------------\n");
+               vty_out(vty, "%-13s %d\n",
+                       "Ledger:", skiplist_count(lp->ledger));
+               vty_out(vty, "%-13s %d\n", "InUse:", skiplist_count(lp->inuse));
+               vty_out(vty, "%-13s %zu\n",
+                       "Requests:", lp_fifo_count(&lp->requests));
+               vty_out(vty, "%-13s %d\n",
+                       "LabelChunks:", listcount(lp->chunks));
+               vty_out(vty, "%-13s %d\n", "Pending:", lp->pending_count);
+               vty_out(vty, "%-13s %d\n", "Reconnects:", lp->reconnect_count);
+       }
+       return CMD_SUCCESS;
+}
+
+DEFUN(show_bgp_labelpool_ledger, show_bgp_labelpool_ledger_cmd,
+      "show bgp labelpool ledger [json]",
+      SHOW_STR BGP_STR
+      "BGP Labelpool information\n"
+      "BGP Labelpool ledger\n" JSON_STR)
+{
+       bool uj = use_json(argc, argv);
+       json_object *json = NULL, *json_elem = NULL;
+       struct lp_lcb *lcb = NULL;
+       struct bgp_dest *dest;
+       void *cursor = NULL;
+       const struct prefix *p;
+       int rc, count;
+
+       if (!lp) {
+               if (uj)
+                       vty_out(vty, "{}\n");
+               else
+                       vty_out(vty, "No existing BGP labelpool\n");
+               return (CMD_WARNING);
+       }
+
+       if (uj) {
+               count = skiplist_count(lp->ledger);
+               if (!count) {
+                       vty_out(vty, "{}\n");
+                       return CMD_SUCCESS;
+               }
+               json = json_object_new_array();
+       } else {
+               vty_out(vty, "Prefix                Label\n");
+               vty_out(vty, "---------------------------\n");
+       }
+
+       for (rc = skiplist_next(lp->ledger, (void **)&dest, (void **)&lcb,
+                               &cursor);
+            !rc; rc = skiplist_next(lp->ledger, (void **)&dest, (void **)&lcb,
+                                    &cursor)) {
+               if (uj) {
+                       json_elem = json_object_new_object();
+                       json_object_array_add(json, json_elem);
+               }
+               switch (lcb->type) {
+               case LP_TYPE_BGP_LU:
+                       if (!CHECK_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED))
+                               if (uj) {
+                                       json_object_string_add(
+                                               json_elem, "prefix", "INVALID");
+                                       json_object_int_add(json_elem, "label",
+                                                           lcb->label);
+                               } else
+                                       vty_out(vty, "%-18s         %u\n",
+                                               "INVALID", lcb->label);
+                       else {
+                               char buf[PREFIX2STR_BUFFER];
+                               p = bgp_dest_get_prefix(dest);
+                               prefix2str(p, buf, sizeof(buf));
+                               if (uj) {
+                                       json_object_string_add(json_elem,
+                                                              "prefix", buf);
+                                       json_object_int_add(json_elem, "label",
+                                                           lcb->label);
+                               } else
+                                       vty_out(vty, "%-18s    %u\n", buf,
+                                               lcb->label);
+                       }
+                       break;
+               case LP_TYPE_VRF:
+                       if (uj) {
+                               json_object_string_add(json_elem, "prefix",
+                                                      "VRF");
+                               json_object_int_add(json_elem, "label",
+                                                   lcb->label);
+                       } else
+                               vty_out(vty, "%-18s         %u\n", "VRF",
+                                       lcb->label);
+
+                       break;
+               }
+       }
+       if (uj) {
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+       return CMD_SUCCESS;
+}
+
+DEFUN(show_bgp_labelpool_inuse, show_bgp_labelpool_inuse_cmd,
+      "show bgp labelpool inuse [json]",
+      SHOW_STR BGP_STR
+      "BGP Labelpool information\n"
+      "BGP Labelpool inuse\n" JSON_STR)
+{
+       bool uj = use_json(argc, argv);
+       json_object *json = NULL, *json_elem = NULL;
+       struct bgp_dest *dest;
+       mpls_label_t label;
+       struct lp_lcb *lcb;
+       void *cursor = NULL;
+       const struct prefix *p;
+       int rc, count;
+
+       if (!lp) {
+               vty_out(vty, "No existing BGP labelpool\n");
+               return (CMD_WARNING);
+       }
+       if (!lp) {
+               if (uj)
+                       vty_out(vty, "{}\n");
+               else
+                       vty_out(vty, "No existing BGP labelpool\n");
+               return (CMD_WARNING);
+       }
+
+       if (uj) {
+               count = skiplist_count(lp->inuse);
+               if (!count) {
+                       vty_out(vty, "{}\n");
+                       return CMD_SUCCESS;
+               }
+               json = json_object_new_array();
+       } else {
+               vty_out(vty, "Prefix                Label\n");
+               vty_out(vty, "---------------------------\n");
+       }
+       for (rc = skiplist_next(lp->inuse, (void **)&label, (void **)&dest,
+                               &cursor);
+            !rc; rc = skiplist_next(lp->ledger, (void **)&label,
+                                    (void **)&dest, &cursor)) {
+               if (skiplist_search(lp->ledger, dest, (void **)&lcb))
+                       continue;
+
+               if (uj) {
+                       json_elem = json_object_new_object();
+                       json_object_array_add(json, json_elem);
+               }
+
+               switch (lcb->type) {
+               case LP_TYPE_BGP_LU:
+                       if (!CHECK_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED))
+                               if (uj) {
+                                       json_object_string_add(
+                                               json_elem, "prefix", "INVALID");
+                                       json_object_int_add(json_elem, "label",
+                                                           label);
+                               } else
+                                       vty_out(vty, "INVALID         %u\n",
+                                               label);
+                       else {
+                               char buf[PREFIX2STR_BUFFER];
+                               p = bgp_dest_get_prefix(dest);
+                               prefix2str(p, buf, sizeof(buf));
+                               if (uj) {
+                                       json_object_string_add(json_elem,
+                                                              "prefix", buf);
+                                       json_object_int_add(json_elem, "label",
+                                                           label);
+                               } else
+                                       vty_out(vty, "%-18s    %u\n", buf,
+                                               label);
+                       }
+                       break;
+               case LP_TYPE_VRF:
+                       if (uj) {
+                               json_object_string_add(json_elem, "prefix",
+                                                      "VRF");
+                               json_object_int_add(json_elem, "label", label);
+                       } else
+                               vty_out(vty, "%-18s         %u\n", "VRF",
+                                       label);
+                       break;
+               }
+       }
+       if (uj) {
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+       return CMD_SUCCESS;
+}
+
+DEFUN(show_bgp_labelpool_requests, show_bgp_labelpool_requests_cmd,
+      "show bgp labelpool requests [json]",
+      SHOW_STR BGP_STR
+      "BGP Labelpool information\n"
+      "BGP Labelpool requests\n" JSON_STR)
+{
+       bool uj = use_json(argc, argv);
+       json_object *json = NULL, *json_elem = NULL;
+       struct bgp_dest *dest;
+       const struct prefix *p;
+       char buf[PREFIX2STR_BUFFER];
+       struct lp_fifo *item, *next;
+       int count;
+
+       if (!lp) {
+               if (uj)
+                       vty_out(vty, "{}\n");
+               else
+                       vty_out(vty, "No existing BGP labelpool\n");
+               return (CMD_WARNING);
+       }
+
+       if (uj) {
+               count = lp_fifo_count(&lp->requests);
+               if (!count) {
+                       vty_out(vty, "{}\n");
+                       return CMD_SUCCESS;
+               }
+               json = json_object_new_array();
+       } else {
+               vty_out(vty, "Prefix         \n");
+               vty_out(vty, "----------------\n");
+       }
+
+       for (item = lp_fifo_first(&lp->requests); item; item = next) {
+               next = lp_fifo_next_safe(&lp->requests, item);
+               dest = item->lcb.labelid;
+               if (uj) {
+                       json_elem = json_object_new_object();
+                       json_object_array_add(json, json_elem);
+               }
+               switch (item->lcb.type) {
+               case LP_TYPE_BGP_LU:
+                       if (!CHECK_FLAG(dest->flags,
+                                       BGP_NODE_LABEL_REQUESTED)) {
+                               if (uj)
+                                       json_object_string_add(
+                                               json_elem, "prefix", "INVALID");
+                               else
+                                       vty_out(vty, "INVALID\n");
+                       } else {
+                               p = bgp_dest_get_prefix(dest);
+                               prefix2str(p, buf, sizeof(buf));
+                               if (uj)
+                                       json_object_string_add(json_elem,
+                                                              "prefix", buf);
+                               else
+                                       vty_out(vty, "%-18s\n", buf);
+                       }
+                       break;
+               case LP_TYPE_VRF:
+                       if (uj)
+                               json_object_string_add(json_elem, "prefix",
+                                                      "VRF");
+                       else
+                               vty_out(vty, "VRF\n");
+                       break;
+               }
+       }
+       if (uj) {
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+       return CMD_SUCCESS;
+}
+
+DEFUN(show_bgp_labelpool_chunks, show_bgp_labelpool_chunks_cmd,
+      "show bgp labelpool chunks [json]",
+      SHOW_STR BGP_STR
+      "BGP Labelpool information\n"
+      "BGP Labelpool chunks\n" JSON_STR)
+{
+       bool uj = use_json(argc, argv);
+       json_object *json = NULL, *json_elem;
+       struct listnode *node;
+       struct lp_chunk *chunk;
+       int count;
+
+       if (!lp) {
+               if (uj)
+                       vty_out(vty, "{}\n");
+               else
+                       vty_out(vty, "No existing BGP labelpool\n");
+               return (CMD_WARNING);
+       }
+
+       if (uj) {
+               count = listcount(lp->chunks);
+               if (!count) {
+                       vty_out(vty, "{}\n");
+                       return CMD_SUCCESS;
+               }
+               json = json_object_new_array();
+       } else {
+               vty_out(vty, "First    Last\n");
+               vty_out(vty, "--------------\n");
+       }
+
+       for (ALL_LIST_ELEMENTS_RO(lp->chunks, node, chunk)) {
+               if (uj) {
+                       json_elem = json_object_new_object();
+                       json_object_array_add(json, json_elem);
+                       json_object_int_add(json_elem, "first", chunk->first);
+                       json_object_int_add(json_elem, "last", chunk->last);
+               } else
+                       vty_out(vty, "%-10u %-10u\n", chunk->first,
+                               chunk->last);
+       }
+       if (uj) {
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+       return CMD_SUCCESS;
+}
+
+void bgp_lp_vty_init(void)
+{
+       install_element(VIEW_NODE, &show_bgp_labelpool_summary_cmd);
+       install_element(VIEW_NODE, &show_bgp_labelpool_ledger_cmd);
+       install_element(VIEW_NODE, &show_bgp_labelpool_inuse_cmd);
+       install_element(VIEW_NODE, &show_bgp_labelpool_requests_cmd);
+       install_element(VIEW_NODE, &show_bgp_labelpool_chunks_cmd);
+}
index eaa3fce20b107dc793d9f8980058f12cddc83b78..d9f64acfe40002f25d4e87492c151cf83f8c8ce0 100644 (file)
@@ -40,6 +40,7 @@ struct labelpool {
        struct lp_fifo_head     requests;       /* blocked on zebra */
        struct work_queue       *callback_q;
        uint32_t                pending_count;  /* requested from zebra */
+       uint32_t reconnect_count;               /* zebra reconnections */
 };
 
 extern void bgp_lp_init(struct thread_master *master, struct labelpool *pool);
@@ -50,5 +51,6 @@ extern void bgp_lp_release(int type, void *labelid, mpls_label_t label);
 extern void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last);
 extern void bgp_lp_event_zebra_down(void);
 extern void bgp_lp_event_zebra_up(void);
+extern void bgp_lp_vty_init(void);
 
 #endif /* _FRR_BGP_LABELPOOL_H */
index 5900fcf862b91c2ab6c4d710be4ea55ee06ac17d..88a85c979e74c06c330a51c51bd139718df11cc3 100644 (file)
@@ -348,16 +348,12 @@ void lcommunity_finish(void)
        lcomhash = NULL;
 }
 
-/* Large Communities token enum. */
-enum lcommunity_token {
-       lcommunity_token_unknown = 0,
-       lcommunity_token_val,
-};
-
-/* Get next Large Communities token from the string. */
+/* Get next Large Communities token from the string.
+ * Assumes str is space-delimeted and describes 0 or more
+ * valid large communities
+ */
 static const char *lcommunity_gettoken(const char *str,
-                                      struct lcommunity_val *lval,
-                                      enum lcommunity_token *token)
+                                      struct lcommunity_val *lval)
 {
        const char *p = str;
 
@@ -372,60 +368,55 @@ static const char *lcommunity_gettoken(const char *str,
                return NULL;
 
        /* Community value. */
-       if (isdigit((unsigned char)*p)) {
-               int separator = 0;
-               int digit = 0;
-               uint32_t globaladmin = 0;
-               uint32_t localdata1 = 0;
-               uint32_t localdata2 = 0;
-
-               while (isdigit((unsigned char)*p) || *p == ':') {
-                       if (*p == ':') {
-                               if (separator == 2) {
-                                       *token = lcommunity_token_unknown;
-                                       return NULL;
-                               } else {
-                                       separator++;
-                                       digit = 0;
-                                       if (separator == 1) {
-                                               globaladmin = localdata2;
-                                       } else {
-                                               localdata1 = localdata2;
-                                       }
-                                       localdata2 = 0;
-                               }
+       int separator = 0;
+       int digit = 0;
+       uint32_t globaladmin = 0;
+       uint32_t localdata1 = 0;
+       uint32_t localdata2 = 0;
+
+       while (*p && *p != ' ') {
+               /* large community valid chars */
+               assert(isdigit((unsigned char)*p) || *p == ':');
+
+               if (*p == ':') {
+                       separator++;
+                       digit = 0;
+                       if (separator == 1) {
+                               globaladmin = localdata2;
                        } else {
-                               digit = 1;
-                               localdata2 *= 10;
-                               localdata2 += (*p - '0');
+                               localdata1 = localdata2;
                        }
-                       p++;
+                       localdata2 = 0;
+               } else {
+                       digit = 1;
+                       /* left shift the accumulated value and add current
+                        * digit
+                        */
+                       localdata2 *= 10;
+                       localdata2 += (*p - '0');
                }
-               if (!digit) {
-                       *token = lcommunity_token_unknown;
-                       return NULL;
-               }
-
-               /*
-                * Copy the large comm.
-                */
-               lval->val[0] = (globaladmin >> 24) & 0xff;
-               lval->val[1] = (globaladmin >> 16) & 0xff;
-               lval->val[2] = (globaladmin >> 8) & 0xff;
-               lval->val[3] = globaladmin & 0xff;
-               lval->val[4] = (localdata1 >> 24) & 0xff;
-               lval->val[5] = (localdata1 >> 16) & 0xff;
-               lval->val[6] = (localdata1 >> 8) & 0xff;
-               lval->val[7] = localdata1 & 0xff;
-               lval->val[8] = (localdata2 >> 24) & 0xff;
-               lval->val[9] = (localdata2 >> 16) & 0xff;
-               lval->val[10] = (localdata2 >> 8) & 0xff;
-               lval->val[11] = localdata2 & 0xff;
-
-               *token = lcommunity_token_val;
-               return p;
+               p++;
        }
-       *token = lcommunity_token_unknown;
+
+       /* Assert str was a valid large community */
+       assert(separator == 2 && digit == 1);
+
+       /*
+        * Copy the large comm.
+        */
+       lval->val[0] = (globaladmin >> 24) & 0xff;
+       lval->val[1] = (globaladmin >> 16) & 0xff;
+       lval->val[2] = (globaladmin >> 8) & 0xff;
+       lval->val[3] = globaladmin & 0xff;
+       lval->val[4] = (localdata1 >> 24) & 0xff;
+       lval->val[5] = (localdata1 >> 16) & 0xff;
+       lval->val[6] = (localdata1 >> 8) & 0xff;
+       lval->val[7] = localdata1 & 0xff;
+       lval->val[8] = (localdata2 >> 24) & 0xff;
+       lval->val[9] = (localdata2 >> 16) & 0xff;
+       lval->val[10] = (localdata2 >> 8) & 0xff;
+       lval->val[11] = localdata2 & 0xff;
+
        return p;
 }
 
@@ -439,23 +430,16 @@ static const char *lcommunity_gettoken(const char *str,
 struct lcommunity *lcommunity_str2com(const char *str)
 {
        struct lcommunity *lcom = NULL;
-       enum lcommunity_token token = lcommunity_token_unknown;
        struct lcommunity_val lval;
 
+       if (!lcommunity_list_valid(str, LARGE_COMMUNITY_LIST_STANDARD))
+               return NULL;
+
        do {
-               str = lcommunity_gettoken(str, &lval, &token);
-               switch (token) {
-               case lcommunity_token_val:
-                       if (lcom == NULL)
-                               lcom = lcommunity_new();
-                       lcommunity_add_val(lcom, &lval);
-                       break;
-               case lcommunity_token_unknown:
-               default:
-                       if (lcom)
-                               lcommunity_free(&lcom);
-                       return NULL;
-               }
+               str = lcommunity_gettoken(str, &lval);
+               if (lcom == NULL)
+                       lcom = lcommunity_new();
+               lcommunity_add_val(lcom, &lval);
        } while (str);
 
        return lcom;
index c96df8482ddbe5eeae7a1050b83b1ea02164fd12..6ccb6b7879e4520a747068bdd26f037e8a6aa555 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "lib/json.h"
 #include "bgpd/bgp_route.h"
+#include "bgpd/bgp_clist.h"
 
 /* Large Communities value is twelve octets long.  */
 #define LCOMMUNITY_SIZE                        12
index 21c880e95b2b79133f1130f588b87981373b9844..3cb3d06217a3884288688b6f175532c16d4639ed 100644 (file)
 #include "bgpd/bgp_keepalives.h"
 #include "bgpd/bgp_network.h"
 #include "bgpd/bgp_errors.h"
+#include "bgpd/bgp_script.h"
 #include "lib/routing_nb.h"
 #include "bgpd/bgp_nb.h"
 #include "bgpd/bgp_evpn_mh.h"
+#include "bgpd/bgp_nht.h"
 
 #ifdef ENABLE_BGP_VNC
 #include "bgpd/rfapi/rfapi_backend.h"
@@ -209,6 +211,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
                bgp_delete(bgp_default);
 
        bgp_evpn_mh_finish();
+       bgp_l3nhg_finish();
 
        /* reverse bgp_dump_init */
        bgp_dump_finish();
@@ -251,6 +254,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
 
        bf_free(bm->rd_idspace);
        list_delete(&bm->bgp);
+       list_delete(&bm->addresses);
 
        bgp_lp_finish();
 
@@ -402,12 +406,16 @@ int main(int argc, char **argv)
        int tmp_port;
 
        int bgp_port = BGP_PORT_DEFAULT;
-       char *bgp_address = NULL;
+       struct list *addresses = list_new();
        int no_fib_flag = 0;
        int no_zebra_flag = 0;
        int skip_runas = 0;
        int instance = 0;
        int buffer_size = BGP_SOCKET_SNDBUF_SIZE;
+       char *address;
+       struct listnode *node;
+
+       addresses->cmp = (int (*)(void *, void *))strcmp;
 
        frr_preinit(&bgpd_di, argc, argv);
        frr_opt_add(
@@ -461,7 +469,7 @@ int main(int argc, char **argv)
                        break;
                }
                case 'l':
-                       bgp_address = optarg;
+                       listnode_add_sort_nodup(addresses, optarg);
                /* listenon implies -n */
                /* fallthru */
                case 'n':
@@ -491,11 +499,10 @@ int main(int argc, char **argv)
                memset(&bgpd_privs, 0, sizeof(bgpd_privs));
 
        /* BGP master init. */
-       bgp_master_init(frr_init(), buffer_size);
+       bgp_master_init(frr_init(), buffer_size, addresses);
        bm->port = bgp_port;
        if (bgp_port == 0)
                bgp_option_set(BGP_OPT_NO_LISTEN);
-       bm->address = bgp_address;
        if (no_fib_flag || no_zebra_flag)
                bgp_option_set(BGP_OPT_NO_FIB);
        if (no_zebra_flag)
@@ -504,6 +511,10 @@ int main(int argc, char **argv)
        /* Initializations. */
        bgp_vrf_init();
 
+#ifdef HAVE_SCRIPTING
+       bgp_script_init();
+#endif
+
        hook_register(routing_conf_event,
                      routing_control_plane_protocols_name_validate);
 
@@ -511,8 +522,16 @@ int main(int argc, char **argv)
        /* BGP related initialization.  */
        bgp_init((unsigned short)instance);
 
-       snprintf(bgpd_di.startinfo, sizeof(bgpd_di.startinfo), ", bgp@%s:%d",
-                (bm->address ? bm->address : "<all>"), bm->port);
+       if (list_isempty(bm->addresses)) {
+               snprintf(bgpd_di.startinfo, sizeof(bgpd_di.startinfo),
+                        ", bgp@<all>:%d", bm->port);
+       } else {
+               for (ALL_LIST_ELEMENTS_RO(bm->addresses, node, address))
+                       snprintf(bgpd_di.startinfo + strlen(bgpd_di.startinfo),
+                                sizeof(bgpd_di.startinfo)
+                                        - strlen(bgpd_di.startinfo),
+                                ", bgp@%s:%d", address, bm->port);
+       }
 
        frr_config_fork();
        /* must be called after fork() */
index d8fc98e0484209b68763f2b3abcac2b95e4d4c2a..0013eb2df2a575239799c407513e8f956d3f1bd2 100644 (file)
@@ -98,6 +98,7 @@ DEFINE_MTYPE(BGPD, PEER_UPDATE_SOURCE, "BGP peer update interface")
 DEFINE_MTYPE(BGPD, PEER_CONF_IF, "BGP peer config interface")
 DEFINE_MTYPE(BGPD, BGP_DAMP_INFO, "Dampening info")
 DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array")
+DEFINE_MTYPE(BGPD, BGP_DAMP_REUSELIST, "BGP Dampening reuse list")
 DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp")
 DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate")
 DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address")
@@ -118,9 +119,11 @@ DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
 DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information")
 DEFINE_MTYPE(BGPD, BGP_EVPN_MH_INFO, "BGP EVPN MH Information")
 DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VTEP, "BGP EVPN ES VTEP")
+DEFINE_MTYPE(BGPD, BGP_EVPN_PATH_ES_INFO, "BGP EVPN PATH ES Information")
 DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI_VTEP, "BGP EVPN ES-EVI VTEP")
 DEFINE_MTYPE(BGPD, BGP_EVPN_ES, "BGP EVPN ESI Information")
 DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI, "BGP EVPN ES-per-EVI Information")
+DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VRF, "BGP EVPN ES-per-VRF Information")
 DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT")
 DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT")
 DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP")
index d1ae392c65ad5605f642d3b2ec7a87f961fc9918..63998e95acb5e7d469154d45ba139b750063874f 100644 (file)
@@ -94,6 +94,7 @@ DECLARE_MTYPE(PEER_UPDATE_SOURCE)
 DECLARE_MTYPE(PEER_CONF_IF)
 DECLARE_MTYPE(BGP_DAMP_INFO)
 DECLARE_MTYPE(BGP_DAMP_ARRAY)
+DECLARE_MTYPE(BGP_DAMP_REUSELIST)
 DECLARE_MTYPE(BGP_REGEXP)
 DECLARE_MTYPE(BGP_AGGREGATE)
 DECLARE_MTYPE(BGP_ADDR)
@@ -114,7 +115,9 @@ DECLARE_MTYPE(LCOMMUNITY_VAL)
 DECLARE_MTYPE(BGP_EVPN_MH_INFO)
 DECLARE_MTYPE(BGP_EVPN_ES)
 DECLARE_MTYPE(BGP_EVPN_ES_EVI)
+DECLARE_MTYPE(BGP_EVPN_ES_VRF)
 DECLARE_MTYPE(BGP_EVPN_ES_VTEP)
+DECLARE_MTYPE(BGP_EVPN_PATH_ES_INFO)
 DECLARE_MTYPE(BGP_EVPN_ES_EVI_VTEP)
 
 DECLARE_MTYPE(BGP_EVPN)
index 662c5da414954607a89df35b8bdb62138de4ac66..1d66d75288ef36e4cb5389d1a13063e216c2dedb 100644 (file)
@@ -419,8 +419,7 @@ int vpn_leak_label_callback(
 
 static bool ecom_intersect(struct ecommunity *e1, struct ecommunity *e2)
 {
-       int i;
-       int j;
+       uint32_t i, j;
 
        if (!e1 || !e2)
                return false;
@@ -1703,6 +1702,8 @@ void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
        if (!is_inst_match)
                listnode_add(to_bgp->vpn_policy[afi].import_vrf,
                                     vname);
+       else
+               XFREE(MTYPE_TMP, vname);
 
        /* Check if the source vrf already exports to any vrf,
         * first time export requires to setup auto derived RD/RT values.
@@ -1725,6 +1726,9 @@ void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
        if (!is_inst_match)
                listnode_add(from_bgp->vpn_policy[afi].export_vrf,
                             vname);
+       else
+               XFREE(MTYPE_TMP, vname);
+
        /* Update import RT for current VRF using export RT of the VRF we're
         * importing from. First though, make sure "import_vrf" has that
         * set.
@@ -1755,19 +1759,26 @@ void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
 
        if (debug) {
                const char *from_name;
+               char *ecom1, *ecom2;
 
                from_name = from_bgp->name ? from_bgp->name :
                        VRF_DEFAULT_NAME;
-               zlog_debug("%s from %s to %s first_export %u import-rt %s export-rt %s",
-                          __func__, from_name, export_name, first_export,
-                          to_bgp->vpn_policy[afi].rtlist[idir] ?
-                          (ecommunity_ecom2str(to_bgp->vpn_policy[afi].
-                                               rtlist[idir],
-                                       ECOMMUNITY_FORMAT_ROUTE_MAP, 0)) : " ",
-                          to_bgp->vpn_policy[afi].rtlist[edir] ?
-                          (ecommunity_ecom2str(to_bgp->vpn_policy[afi].
-                                               rtlist[edir],
-                                       ECOMMUNITY_FORMAT_ROUTE_MAP, 0)) : " ");
+
+               ecom1 = ecommunity_ecom2str(
+                       to_bgp->vpn_policy[afi].rtlist[idir],
+                       ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+
+               ecom2 = ecommunity_ecom2str(
+                       to_bgp->vpn_policy[afi].rtlist[edir],
+                       ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+
+               zlog_debug(
+                       "%s from %s to %s first_export %u import-rt %s export-rt %s",
+                       __func__, from_name, export_name, first_export, ecom1,
+                       ecom2);
+
+               ecommunity_strfree(&ecom1);
+               ecommunity_strfree(&ecom2);
        }
 
        /* Does "import_vrf" first need to export its routes or that
index f098332b2917f908cbef3ddddd1925da449f0255..f65a4be677d8979733775383b5f0bef0575917bf 100644 (file)
@@ -351,6 +351,13 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .modify = bgp_global_ebgp_requires_policy_modify,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/global/suppress-duplicates",
+                       .cbs = {
+                               .cli_show = cli_show_router_bgp_suppress_duplicates,
+                               .modify = bgp_global_suppress_duplicates_modify,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/global/show-hostname",
                        .cbs = {
@@ -3084,6 +3091,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/add-paths/path-type",
                        .cbs = {
@@ -3316,6 +3393,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/add-paths/path-type",
                        .cbs = {
@@ -3548,6 +3695,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/add-paths/path-type",
                        .cbs = {
@@ -3780,6 +3997,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/add-paths/path-type",
                        .cbs = {
@@ -4012,6 +4299,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/add-paths/path-type",
                        .cbs = {
@@ -4204,6 +4561,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/add-paths/path-type",
                        .cbs = {
@@ -4397,35 +4824,105 @@ const struct frr_yang_module_info frr_bgp_info = {
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-as",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/rmap-import",
                        .cbs = {
-                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_modify,
-                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_destroy,
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_import_destroy,
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-origin-as",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/rmap-export",
                        .cbs = {
-                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_modify,
-                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_destroy,
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_export_destroy,
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/replace-peer-as",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/plist-import",
                        .cbs = {
-                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_replace_peer_as_modify,
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_import_destroy,
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/as-path-unchanged",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/plist-export",
                        .cbs = {
-                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_as_path_unchanged_modify,
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_export_destroy,
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/next-hop-unchanged",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/access-list-import",
                        .cbs = {
-                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_next_hop_unchanged_modify,
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-as",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-origin-as",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/replace-peer-as",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_replace_peer_as_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/as-path-unchanged",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_as_path_unchanged_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/next-hop-unchanged",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_next_hop_unchanged_modify,
                        }
                },
                {
@@ -4464,6 +4961,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_soft_reconfiguration_modify,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/route-reflector/route-reflector-client",
                        .cbs = {
@@ -4482,6 +5049,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_soft_reconfiguration_modify,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/route-reflector/route-reflector-client",
                        .cbs = {
@@ -4500,6 +5137,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_soft_reconfiguration_modify,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/add-paths/path-type",
                        .cbs = {
@@ -5040,6 +5747,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/add-paths/path-type",
                        .cbs = {
@@ -5271,6 +6048,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/add-paths/path-type",
                        .cbs = {
@@ -5503,15 +6350,85 @@ const struct frr_yang_module_info frr_bgp_info = {
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/add-paths/path-type",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/rmap-import",
                        .cbs = {
-                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_add_paths_path_type_modify,
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_destroy,
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/allow-own-as",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/rmap-export",
                        .cbs = {
-                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_modify,
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/add-paths/path-type",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_add_paths_path_type_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/allow-own-as",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_modify,
                                .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_destroy,
                        }
                },
@@ -5734,6 +6651,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/add-paths/path-type",
                        .cbs = {
@@ -6436,6 +7423,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_soft_reconfiguration_modify,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/route-reflector/route-reflector-client",
                        .cbs = {
@@ -6454,6 +7511,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_soft_reconfiguration_modify,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/add-paths/path-type",
                        .cbs = {
@@ -6994,6 +8121,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/add-paths/path-type",
                        .cbs = {
@@ -7232,6 +8429,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/add-paths/path-type",
                        .cbs = {
@@ -7471,35 +8738,105 @@ const struct frr_yang_module_info frr_bgp_info = {
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/add-paths/path-type",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/rmap-import",
                        .cbs = {
-                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_add_paths_path_type_modify,
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_destroy,
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/allow-own-as",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/rmap-export",
                        .cbs = {
-                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_modify,
-                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_destroy,
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_destroy,
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/allow-own-origin-as",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/plist-import",
                        .cbs = {
-                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_origin_as_modify,
-                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_origin_as_destroy,
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_destroy,
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/replace-peer-as",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/plist-export",
                        .cbs = {
-                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_replace_peer_as_modify,
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_destroy,
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/default-originate",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/access-list-import",
                        .cbs = {
-                               .apply_finish = bgp_peer_group_afi_safi_default_originate_apply_finish,
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/add-paths/path-type",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_add_paths_path_type_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/allow-own-as",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/allow-own-origin-as",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_origin_as_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_origin_as_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/replace-peer-as",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_replace_peer_as_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/default-originate",
+                       .cbs = {
+                               .apply_finish = bgp_peer_group_afi_safi_default_originate_apply_finish,
                        }
                },
                {
@@ -7702,6 +9039,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/add-paths/path-type",
                        .cbs = {
@@ -7934,6 +9341,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/add-paths/path-type",
                        .cbs = {
@@ -8126,6 +9603,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/add-paths/path-type",
                        .cbs = {
@@ -8318,6 +9865,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weight_attribute_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-as",
                        .cbs = {
@@ -8404,6 +10021,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_soft_reconfiguration_modify,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/route-reflector/route-reflector-client",
                        .cbs = {
@@ -8422,6 +10109,76 @@ const struct frr_yang_module_info frr_bgp_info = {
                                .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_soft_reconfiguration_modify,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/rmap-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/rmap-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/plist-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/plist-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/access-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/access-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/as-path-filter-list-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/as-path-filter-list-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/unsuppress-map-import",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/unsuppress-map-export",
+                       .cbs = {
+                               .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_modify,
+                               .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_destroy,
+                       }
+               },
                {
                        .xpath = NULL,
                },
index f608d4f8c14bc1b5572692e93d9cb5e48fa09b5e..eb7725d3ddf7b9c2008b6f1fd118016224ba5075 100644 (file)
@@ -127,6 +127,7 @@ int bgp_global_fast_external_failover_modify(struct nb_cb_modify_args *args);
 int bgp_global_local_pref_modify(struct nb_cb_modify_args *args);
 int bgp_global_default_shutdown_modify(struct nb_cb_modify_args *args);
 int bgp_global_ebgp_requires_policy_modify(struct nb_cb_modify_args *args);
+int bgp_global_suppress_duplicates_modify(struct nb_cb_modify_args *args);
 int bgp_global_show_hostname_modify(struct nb_cb_modify_args *args);
 int bgp_global_show_nexthop_hostname_modify(struct nb_cb_modify_args *args);
 int bgp_global_import_check_modify(struct nb_cb_modify_args *args);
@@ -1328,6 +1329,46 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_soft_reconfiguration_
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_modify(
        struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_add_paths_path_type_modify(
@@ -1430,6 +1471,46 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_weight_weight_attri
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_as_modify(
@@ -1530,6 +1611,46 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_weight_weight_attri
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_modify(
@@ -1630,6 +1751,46 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_as_modify(
@@ -1730,6 +1891,46 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_weight_weight
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_as_modify(
@@ -1812,6 +2013,46 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weight_a
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_as_modify(
@@ -1894,6 +2135,46 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weight_a
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_destroy(
@@ -1920,18 +2201,138 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_route_server_route_serv
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_as_modify(
@@ -2174,6 +2575,46 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_wei
        struct nb_cb_modify_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_as_modify(
@@ -2274,6 +2715,46 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_weight_w
        struct nb_cb_modify_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_as_modify(
@@ -2374,6 +2855,46 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_weight_w
        struct nb_cb_modify_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_modify(
@@ -2474,6 +2995,46 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_we
        struct nb_cb_modify_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_as_modify(
@@ -2770,12 +3331,92 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_ser
        struct nb_cb_modify_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args);
 int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_as_modify(
@@ -3018,6 +3659,46 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_weight_weight_att
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_as_modify(
@@ -3118,6 +3799,46 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_weight_weight_a
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_as_modify(
@@ -3218,6 +3939,46 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_weight_weight_a
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_modify(
@@ -3318,6 +4079,46 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_weight_we
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_as_modify(
@@ -3418,6 +4219,46 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_weight_we
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_as_modify(
@@ -3500,6 +4341,46 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weig
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_as_modify(
@@ -3582,6 +4463,46 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weig
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_modify(
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_destroy(
@@ -3614,12 +4535,92 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_route_server_rou
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args);
 int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args);
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args);
 
 /*
  * Callback registered with routing_nb lib to validate only
@@ -3639,6 +4640,9 @@ void cli_show_router_bgp_route_selection(struct vty *vty,
 void cli_show_router_bgp_ebgp_requires_policy(struct vty *vty,
                                              struct lyd_node *dnode,
                                              bool show_defaults);
+void cli_show_router_bgp_suppress_duplicates(struct vty *vty,
+                                             struct lyd_node *dnode,
+                                             bool show_defaults);
 void cli_show_router_bgp_default_shutdown(struct vty *vty,
                                          struct lyd_node *dnode,
                                          bool show_defaults);
index f19fcf0f8c1f35adecca2f28c884c837a2188b0d..531ff4a60af2e69c43930ba72bf06490f7e71699 100644 (file)
@@ -279,7 +279,7 @@ int bgp_global_router_id_destroy(struct nb_cb_destroy_args *args)
 
        bgp = nb_running_get_entry(args->dnode, NULL, true);
 
-       router_id.s_addr = 0;
+       router_id.s_addr = INADDR_ANY;
        bgp_router_id_static_set(bgp, router_id);
 
        return NB_OK;
@@ -894,6 +894,9 @@ int bgp_global_route_selection_options_allow_multiple_as_modify(
                                                "../multi-path-as-set")) {
                                SET_FLAG(bgp->flags,
                                         BGP_FLAG_MULTIPATH_RELAX_AS_SET);
+                       } else {
+                               UNSET_FLAG(bgp->flags,
+                                          BGP_FLAG_MULTIPATH_RELAX_AS_SET);
                        }
                } else {
                        UNSET_FLAG(bgp->flags, BGP_FLAG_ASPATH_MULTIPATH_RELAX);
@@ -923,15 +926,10 @@ int bgp_global_route_selection_options_multi_path_as_set_modify(
                return NB_OK;
        case NB_EV_APPLY:
                bgp = nb_running_get_entry(args->dnode, NULL, true);
-
-               if (!CHECK_FLAG(bgp->flags, BGP_FLAG_MULTIPATH_RELAX_AS_SET)) {
+               if (yang_dnode_get_bool(args->dnode, NULL))
                        SET_FLAG(bgp->flags, BGP_FLAG_MULTIPATH_RELAX_AS_SET);
-
-               } else
-                       zlog_debug(
-                               "%s multi-path-as-set as part of allow-multiple-as modify cb.",
-                               __func__);
-
+               else
+                       UNSET_FLAG(bgp->flags, BGP_FLAG_MULTIPATH_RELAX_AS_SET);
                break;
        }
 
@@ -1425,8 +1423,8 @@ int bgp_global_global_config_timers_hold_time_modify(
                keepalive = yang_dnode_get_uint16(args->dnode, "../keepalive");
                holdtime = yang_dnode_get_uint16(args->dnode, NULL);
 
-               bgp_timers_set(bgp, keepalive, holdtime,
-                              DFLT_BGP_CONNECT_RETRY);
+               bgp_timers_set(bgp, keepalive, holdtime, DFLT_BGP_CONNECT_RETRY,
+                              BGP_DEFAULT_DELAYOPEN);
 
                break;
        }
@@ -1466,8 +1464,8 @@ int bgp_global_global_config_timers_keepalive_modify(
                keepalive = yang_dnode_get_uint16(args->dnode, NULL);
                holdtime = yang_dnode_get_uint16(args->dnode, "../hold-time");
 
-               bgp_timers_set(bgp, keepalive, holdtime,
-                              DFLT_BGP_CONNECT_RETRY);
+               bgp_timers_set(bgp, keepalive, holdtime, DFLT_BGP_CONNECT_RETRY,
+                              BGP_DEFAULT_DELAYOPEN);
 
                break;
        }
@@ -1597,6 +1595,27 @@ int bgp_global_ebgp_requires_policy_modify(struct nb_cb_modify_args *args)
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/global/suppress-duplicates
+ */
+int bgp_global_suppress_duplicates_modify(struct nb_cb_modify_args *args)
+{
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       struct bgp *bgp;
+
+       bgp = nb_running_get_entry(args->dnode, NULL, true);
+
+       if (yang_dnode_get_bool(args->dnode, NULL))
+               SET_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES);
+       else
+               UNSET_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES);
+
+       return NB_OK;
+}
+
 /*
  * XPath:
  * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/global/show-hostname
@@ -5213,7 +5232,8 @@ int bgp_neighbors_unnumbered_neighbor_neighbor_remote_as_remote_as_type_destroy(
                peer = peer_lookup_by_conf_if(bgp, peer_str);
 
                /* remote-as set to 0 and as_type to unspecified */
-               peer_as_change(peer, 0, AS_UNSPECIFIED);
+               if (peer)
+                       peer_as_change(peer, 0, AS_UNSPECIFIED);
 
                break;
        }
@@ -6291,7 +6311,11 @@ static struct peer *bgp_peer_group_peer_lookup(struct bgp *bgp,
        struct peer_group *group = NULL;
 
        group = peer_group_lookup(bgp, peer_str);
-       return group->conf;
+
+       if (group)
+               return group->conf;
+
+       return NULL;
 }
 
 /*
@@ -9530,7 +9554,7 @@ static int bgp_global_afi_safi_ip_unicast_vpn_config_rd_destroy(
        bgp = nb_running_get_entry(af_dnode, NULL, true);
 
        rd_str = yang_dnode_get_string(args->dnode, NULL);
-       if (str2prefix_rd(rd_str, &prd)) {
+       if (!str2prefix_rd(rd_str, &prd)) {
                snprintf(args->errmsg, args->errmsg_len, "Malformed rd %s \n",
                         rd_str);
                return NB_ERR_INCONSISTENCY;
@@ -15100,6 +15124,66 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_bo
        return NB_OK;
 }
 
+static int bgp_neighbor_afi_safi_rmap_modify(struct nb_cb_modify_args *args,
+                                            int direct)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+       const char *name_str;
+       struct route_map *route_map;
+       int ret;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "neighbor");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./remote-address");
+       peer = bgp_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
+                                       args->errmsg_len);
+
+       name_str = yang_dnode_get_string(args->dnode, NULL);
+       route_map = route_map_lookup_by_name(name_str);
+       ret = peer_route_map_set(peer, afi, safi, direct, name_str, route_map);
+
+       return bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret);
+}
+
+static int bgp_neighbor_afi_safi_rmap_destroy(struct nb_cb_destroy_args *args,
+                                             int direct)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+       int ret;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "neighbor");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./remote-address");
+       peer = bgp_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
+                                       args->errmsg_len);
+
+       ret = peer_route_map_unset(peer, afi, safi, direct);
+
+       return bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret);
+}
+
 /*
  * XPath:
  * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/rmap-import
@@ -15111,9 +15195,9 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_im
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -15126,9 +15210,9 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_im
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -15145,9 +15229,9 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_ex
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_OUT);
        }
 
        return NB_OK;
@@ -15160,14 +15244,72 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_ex
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_OUT);
        }
 
        return NB_OK;
 }
 
+static int bgp_neighbor_afi_safi_plist_modify(struct nb_cb_modify_args *args,
+                                             int direct)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+       const char *name_str;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "neighbor");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./remote-address");
+       peer = bgp_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
+                                       args->errmsg_len);
+
+       name_str = yang_dnode_get_string(args->dnode, NULL);
+       if (peer_prefix_list_set(peer, afi, safi, direct, name_str) < 0)
+               return NB_ERR_INCONSISTENCY;
+
+       return NB_OK;
+}
+
+static int bgp_neighbor_afi_safi_plist_destroy(struct nb_cb_destroy_args *args,
+                                              int direct)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "neighbor");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./remote-address");
+       peer = bgp_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
+                                       args->errmsg_len);
+
+       if (peer_prefix_list_unset(peer, afi, safi, direct) < 0)
+               return NB_ERR_INCONSISTENCY;
+
+       return NB_OK;
+}
+
 /*
  * XPath:
  * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/plist-import
@@ -15179,9 +15321,9 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_i
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_IN);
        }
 
        return NB_OK;
@@ -15194,9 +15336,9 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_i
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_destroy(args, FILTER_IN);
        }
 
        return NB_OK;
@@ -15213,9 +15355,9 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_e
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -15228,9 +15370,9 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_e
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_destroy(args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -16417,6 +16559,347 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribu
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/rmap-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_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 bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/rmap-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_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 bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/plist-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_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 bgp_neighbor_afi_safi_plist_destroy(args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/plist-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_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 bgp_neighbor_afi_safi_plist_destroy(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/access-list-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/access-list-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/as-path-filter-list-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/as-path-filter-list-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/unsuppress-map-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/unsuppress-map-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+
 /*
  * XPath:
  * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/add-paths/path-type
@@ -17375,6 +17858,346 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_weight_weight_attri
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/rmap-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_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 bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/rmap-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_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 bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/plist-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_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 bgp_neighbor_afi_safi_plist_destroy(args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/plist-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_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 bgp_neighbor_afi_safi_plist_destroy(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/access-list-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/access-list-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/as-path-filter-list-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/as-path-filter-list-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/unsuppress-map-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/unsuppress-map-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
 /*
  * XPath:
  * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/add-paths/path-type
@@ -18333,6 +19156,346 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_weight_weight_attri
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/rmap-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_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 bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/rmap-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_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 bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/plist-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_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 bgp_neighbor_afi_safi_plist_destroy(args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/plist-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_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 bgp_neighbor_afi_safi_plist_destroy(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/access-list-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/access-list-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/as-path-filter-list-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/as-path-filter-list-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/unsuppress-map-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/unsuppress-map-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
 /*
  * XPath:
  * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/add-paths/path-type
@@ -19291,6 +20454,346 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/rmap-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_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 bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/rmap-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_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 bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/plist-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_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 bgp_neighbor_afi_safi_plist_destroy(args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/plist-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_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 bgp_neighbor_afi_safi_plist_destroy(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/access-list-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/access-list-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/as-path-filter-list-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/as-path-filter-list-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/unsuppress-map-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/unsuppress-map-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
 /*
  * XPath:
  * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/add-paths/path-type
@@ -20249,6 +21752,346 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_weight_weight
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/rmap-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_import_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 bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/rmap-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_export_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 bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/plist-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/plist-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_export_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 bgp_neighbor_afi_safi_plist_destroy(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/access-list-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/access-list-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/as-path-filter-list-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/as-path-filter-list-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/unsuppress-map-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/unsuppress-map-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
 /*
  * XPath:
  * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/add-paths/path-type
@@ -21052,6 +22895,346 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weight_a
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/rmap-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_import_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 bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/rmap-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_export_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 bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/plist-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_destroy(args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/plist-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_export_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 bgp_neighbor_afi_safi_plist_destroy(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/access-list-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/access-list-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/as-path-filter-list-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/as-path-filter-list-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/unsuppress-map-import
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/unsuppress-map-export
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
 /*
  * XPath:
  * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/add-paths/path-type
@@ -21857,33 +24040,33 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weight_a
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/rmap-import
  */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -21891,33 +24074,33 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_o
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/rmap-export
  */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_OUT);
        }
 
        return NB_OK;
@@ -21925,45 +24108,33 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_o
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/plist-import
  */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_replace_peer_as_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_OVERRIDE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_IN);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/as-path-unchanged
- */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_as_path_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_destroy(args, FILTER_IN);
        }
 
        return NB_OK;
@@ -21971,9 +24142,9 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_as_path_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/next-hop-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/plist-export
  */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_next_hop_unchanged_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -21982,34 +24153,22 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_next_hop
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/med-unchanged
- */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_med_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_destroy(args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -22017,44 +24176,32 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_med_unch
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/access-list-import
  */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_nexthop_self_next_hop_self_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/nexthop-self/next-hop-self-force
- */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_nexthop_self_next_hop_self_force_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -22063,44 +24210,32 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_nexthop_self_next_hop_s
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/access-list-export
  */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_route_reflector_route_reflector_client_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/route-server/route-server-client
- */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_route_server_route_server_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -22109,44 +24244,32 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_route_server_route_serv
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/as-path-filter-list-import
  */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_soft_reconfiguration_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/route-reflector/route-reflector-client
- */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_reflector_route_reflector_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -22155,44 +24278,32 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_reflector_rout
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/route-server/route-server-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/as-path-filter-list-export
  */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_server_route_server_client_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/soft-reconfiguration
- */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_soft_reconfiguration_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -22201,44 +24312,32 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_soft_reconfiguration
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/unsuppress-map-import
  */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_route_reflector_route_reflector_client_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/route-server/route-server-client
- */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_route_server_route_server_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -22247,64 +24346,25 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_route_server_route_s
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/unsuppress-map-export
  */
-int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_soft_reconfiguration_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-static int
-bgp_unnumbered_neighbor_afi_safi_flag_modify(struct nb_cb_modify_args *args,
-                                            uint32_t flags, bool set)
-{
-       struct bgp *bgp;
-       const char *peer_str;
-       struct peer *peer;
-       const struct lyd_node *nbr_dnode;
-       const struct lyd_node *nbr_af_dnode;
-       const char *af_name;
-       afi_t afi;
-       safi_t safi;
-
-       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
-       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
-       yang_afi_safi_identity2value(af_name, &afi, &safi);
-
-       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "unnumbered-neighbor");
-       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
-       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
-       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
-                                                  args->errmsg_len);
-
-       if (peer_af_flag_modify_nb(peer, afi, safi, flags, set, args->errmsg,
-                                  args->errmsg_len)
-           < 0)
-               return NB_ERR_INCONSISTENCY;
-
-       return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/add-paths/path-type
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_add_paths_path_type_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -22320,9 +24380,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_add_paths_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_as_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -22337,7 +24397,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_op
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_as_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -22354,9 +24414,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_op
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-origin-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_origin_as_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -22371,7 +24431,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_op
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_origin_as_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -22388,9 +24448,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_op
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/replace-peer-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_options_replace_peer_as_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_replace_peer_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -22399,7 +24459,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_op
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+               return bgp_neighbor_afi_safi_flag_modify(
                        args, PEER_FLAG_AS_OVERRIDE,
                        yang_dnode_get_bool(args->dnode, NULL));
 
@@ -22411,48 +24471,44 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_op
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/default-originate
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/as-path-unchanged
  */
-void bgp_unnumbered_neighbor_afi_safi_default_originate_apply_finish(
-       struct nb_cb_apply_finish_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_as_path_unchanged_modify(
+       struct nb_cb_modify_args *args)
 {
-       struct bgp *bgp;
-       const char *peer_str;
-       struct peer *peer;
-       const struct lyd_node *nbr_dnode;
-       const struct lyd_node *nbr_af_dnode;
-       const char *af_name;
-       afi_t afi;
-       safi_t safi;
-
-       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
-       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
-       yang_afi_safi_identity2value(af_name, &afi, &safi);
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
 
-       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "unnumbered-neighbor");
-       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
-       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
-       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
-                                                  args->errmsg_len);
-       if (!peer)
-               return;
+               break;
+       }
 
-       bgp_peer_afi_safi_default_originate_apply(args, peer, afi, safi);
+       return NB_OK;
 }
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/default-originate/originate
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/next-hop-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_default_originate_originate_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_next_hop_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -22461,72 +24517,44 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_default_or
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/default-originate/route-map
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/med-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_default_originate_route_map_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_med_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_MED_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_default_originate_route_map_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/nexthop-self/next-hop-self
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_nexthop_self_next_hop_self_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
-               break;
-       }
-
-       return NB_OK;
-}
-
-static int bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
-       struct nb_cb_destroy_args *args)
-{
-       struct bgp *bgp;
-       const char *peer_str;
-       struct peer *peer;
-       const struct lyd_node *nbr_dnode;
-       const struct lyd_node *nbr_af_dnode;
-       const char *af_name;
-       afi_t afi;
-       safi_t safi;
-       int direction;
-
-       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
-       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
-       yang_afi_safi_identity2value(af_name, &afi, &safi);
-
-       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "unnumbered-neighbor");
-       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
-       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
-       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
-                                                  args->errmsg_len);
-       if (!peer)
-               return NB_ERR_INCONSISTENCY;
-
-       direction = yang_dnode_get_enum(args->dnode, "./direction");
+               return bgp_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
 
-       switch (direction) {
-       case 1:
-               peer_maximum_prefix_unset(peer, afi, safi);
-               break;
-       case 2:
-               UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT);
-               peer->pmax_out[afi][safi] = 0;
                break;
        }
 
@@ -22535,25 +24563,33 @@ static int bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/nexthop-self/next-hop-self-force
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_create(
-       struct nb_cb_create_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_nexthop_self_next_hop_self_force_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/route-reflector/route-reflector-client
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_route_reflector_route_reflector_client_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -22561,53 +24597,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_lim
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
-                       args);
+               return bgp_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
        }
 
        return NB_OK;
 }
 
-void bgp_unnumbered_neighbor_afi_safi_prefix_limit_apply_finish(
-       struct nb_cb_apply_finish_args *args)
-{
-       struct bgp *bgp;
-       const char *peer_str;
-       struct peer *peer;
-       const struct lyd_node *nbr_dnode;
-       const struct lyd_node *nbr_af_dnode;
-       const char *af_name;
-       afi_t afi;
-       safi_t safi;
-
-       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
-       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
-       yang_afi_safi_identity2value(af_name, &afi, &safi);
-
-       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "unnumbered-neighbor");
-       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
-       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
-       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
-                                                  args->errmsg_len);
-       if (!peer)
-               return;
-
-       bgp_peer_afi_safi_maximum_prefix_set(args, peer, afi, safi);
-}
-
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/route-server/route-server-client
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -22616,17 +24632,21 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/force-check
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/soft-reconfiguration
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_force_check_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -22635,33 +24655,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/rmap-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -22669,33 +24689,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/rmap-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -22703,33 +24723,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/plist-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_destroy(args, FILTER_IN);
        }
 
        return NB_OK;
@@ -22737,33 +24757,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/plist-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_destroy(args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -22771,9 +24791,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/access-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -22788,7 +24808,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_lim
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -22805,9 +24825,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/access-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -22822,7 +24842,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_lim
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -22839,9 +24859,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/as-path-filter-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -22856,7 +24876,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_lim
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -22873,44 +24893,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/as-path-filter-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_nexthop_self_next_hop_self_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/nexthop-self/next-hop-self-force
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_nexthop_self_next_hop_self_force_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -22919,44 +24927,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_nexthop_se
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/unsuppress-map-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_all_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as-all-replace
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_all_replace_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -22965,117 +24961,43 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_private_as
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/unsuppress-map-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as-replace
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_replace_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-static int
-bgp_unnumbered_neighbor_afi_safi_weight_modify(struct nb_cb_modify_args *args)
-{
-       struct bgp *bgp;
-       const char *peer_str;
-       struct peer *peer;
-       const struct lyd_node *nbr_dnode;
-       const char *af_name;
-       uint16_t weight;
-       afi_t afi;
-       safi_t safi;
-       const struct lyd_node *nbr_af_dnode;
-       int ret;
-
-       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
-       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
-       yang_afi_safi_identity2value(af_name, &afi, &safi);
-
-       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "unnumbered-neighbor");
-       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
-       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
-       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
-                                                  args->errmsg_len);
-
-       weight = yang_dnode_get_uint16(args->dnode, NULL);
-
-       ret = peer_weight_set(peer, afi, safi, weight);
-       if (bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret) < 0)
-               return NB_ERR_INCONSISTENCY;
-
-       return NB_OK;
-}
-
-static int
-bgp_unnumbered_neighbor_afi_safi_weight_destroy(struct nb_cb_destroy_args *args)
-{
-       struct bgp *bgp;
-       const char *peer_str;
-       struct peer *peer;
-       const struct lyd_node *nbr_dnode;
-       const struct lyd_node *nbr_af_dnode;
-       const char *af_name;
-       afi_t afi;
-       safi_t safi;
-       int ret;
-
-       bgp = nb_running_get_entry(args->dnode, NULL, true);
-       nbr_dnode = yang_dnode_get_parent(args->dnode, "unnumbered-neighbor");
-       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
-       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
-                                                  args->errmsg_len);
-       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
-       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
-       yang_afi_safi_identity2value(af_name, &afi, &safi);
-
-       ret = peer_weight_unset(peer, afi, safi);
-       if (bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret) < 0)
-               return NB_ERR_INCONSISTENCY;
-
-       return NB_OK;
-}
-
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/route-reflector/route-reflector-client
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_weight_weight_attribute_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -23084,7 +25006,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_weight_wei
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_weight_modify(args);
+               return bgp_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
 
                break;
        }
@@ -23092,8 +25016,12 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_weight_wei
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_weight_weight_attribute_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/route-server/route-server-client
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_server_route_server_client_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -23101,7 +25029,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_weight_wei
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_weight_destroy(args);
+               return bgp_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
 
                break;
        }
@@ -23111,9 +25041,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_weight_wei
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/soft-reconfiguration
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_route_reflector_route_reflector_client_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -23122,8 +25052,8 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_route_refl
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
+               return bgp_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -23134,45 +25064,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_route_refl
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/route-server/route-server-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/rmap-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_route_server_route_server_client_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_IN);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/send-community/send-community
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_send_community_send_community_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -23180,45 +25098,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_send_commu
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/send-community/send-ext-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/rmap-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_send_community_send_ext_community_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/send-community/send-large-community
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_send_community_send_large_community_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_OUT);
        }
 
        return NB_OK;
@@ -23226,45 +25132,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_send_commu
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/plist-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_soft_reconfiguration_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_IN);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/attr-unchanged/as-path-unchanged
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_attr_unchanged_as_path_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_destroy(args, FILTER_IN);
        }
 
        return NB_OK;
@@ -23272,45 +25166,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_attr_uncha
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/attr-unchanged/next-hop-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/plist-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_attr_unchanged_next_hop_unchanged_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/attr-unchanged/med-unchanged
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_attr_unchanged_med_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_destroy(args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -23318,9 +25200,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_attr_uncha
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/orf-capability/orf-send
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/access-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_send_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -23335,7 +25217,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capabi
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_send_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -23352,9 +25234,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capabi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/orf-capability/orf-receive
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/access-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_receive_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -23369,7 +25251,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capabi
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_receive_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -23386,9 +25268,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capabi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/orf-capability/orf-both
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/as-path-filter-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_both_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -23403,7 +25285,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capabi
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_both_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -23420,9 +25302,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capabi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/rmap-import
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/as-path-filter-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_import_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -23437,7 +25319,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_con
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_import_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -23454,9 +25336,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_con
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/rmap-export
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/unsuppress-map-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_export_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -23471,7 +25353,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_con
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_export_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -23488,9 +25370,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_con
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/plist-import
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/unsuppress-map-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_import_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -23505,7 +25387,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_con
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_import_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -23522,32 +25404,21 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_con
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/plist-export
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/route-reflector/route-reflector-client
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_export_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
-               break;
-       }
-
-       return NB_OK;
-}
+               return bgp_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_export_destroy(
-       struct nb_cb_destroy_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
        }
 
@@ -23556,32 +25427,44 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_con
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/access-list-import
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/route-server/route-server-client
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_import_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_import_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/soft-reconfiguration
+ */
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_soft_reconfiguration_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -23590,33 +25473,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_con
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/access-list-export
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/rmap-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_export_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_export_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -23624,33 +25507,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_con
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/as-path-filter-list-import
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/rmap-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_import_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_modify(args, RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_import_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_rmap_destroy(args, RMAP_OUT);
        }
 
        return NB_OK;
@@ -23658,33 +25541,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_con
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/as-path-filter-list-export
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/plist-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_export_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_export_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_destroy(args, FILTER_IN);
        }
 
        return NB_OK;
@@ -23692,33 +25575,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_con
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/unsuppress-map-import
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/plist-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_import_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_modify(args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_import_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_neighbor_afi_safi_plist_destroy(args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -23726,9 +25609,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_con
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/unsuppress-map-export
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/access-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_export_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -23743,7 +25626,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_con
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_export_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -23760,9 +25643,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_con
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/nexthop-local-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/access-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_nexthop_local_unchanged_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -23777,12 +25660,8 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_nexthop_lo
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/add-paths/path-type
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_add_paths_path_type_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -23798,9 +25677,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_add_paths_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/as-path-filter-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_as_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -23815,7 +25694,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_as_path_op
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_as_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -23832,9 +25711,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_as_path_op
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/as-path-filter-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_origin_as_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -23849,7 +25728,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_as_path_op
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_origin_as_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -23866,33 +25745,25 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_as_path_op
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/unsuppress-map-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_as_path_options_replace_peer_as_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_OVERRIDE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/default-originate/originate
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_default_originate_originate_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -23908,9 +25779,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_default_or
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/default-originate/route-map
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/unsuppress-map-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_default_originate_route_map_modify(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -23925,7 +25796,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_default_or
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_default_originate_route_map_destroy(
+int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -23940,23 +25811,50 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_default_or
        return NB_OK;
 }
 
+static int
+bgp_unnumbered_neighbor_afi_safi_flag_modify(struct nb_cb_modify_args *args,
+                                            uint32_t flags, bool set)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "unnumbered-neighbor");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
+       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
+                                                  args->errmsg_len);
+
+       if (peer_af_flag_modify_nb(peer, afi, safi, flags, set, args->errmsg,
+                                  args->errmsg_len)
+           < 0)
+               return NB_ERR_INCONSISTENCY;
+
+       return NB_OK;
+}
+
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/attr-unchanged/as-path-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/add-paths/path-type
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_attr_unchanged_as_path_unchanged_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -23965,44 +25863,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_attr_uncha
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/attr-unchanged/next-hop-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/as-path-options/allow-own-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_attr_unchanged_next_hop_unchanged_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/attr-unchanged/med-unchanged
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_attr_unchanged_med_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_as_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -24011,9 +25897,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_attr_uncha
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/orf-capability/orf-send
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/as-path-options/allow-own-origin-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_send_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_origin_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24028,7 +25914,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capabi
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_send_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_origin_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -24045,25 +25931,64 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capabi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/orf-capability/orf-receive
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/as-path-options/replace-peer-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_receive_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_as_path_options_replace_peer_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_OVERRIDE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_receive_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/default-originate
+ */
+void bgp_unnumbered_neighbor_afi_safi_default_originate_apply_finish(
+       struct nb_cb_apply_finish_args *args)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "unnumbered-neighbor");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
+       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
+                                                  args->errmsg_len);
+       if (!peer)
+               return;
+
+       bgp_peer_afi_safi_default_originate_apply(args, peer, afi, safi);
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/default-originate/originate
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_default_originate_originate_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -24079,9 +26004,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capabi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/orf-capability/orf-both
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/default-originate/route-map
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_both_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_default_originate_route_map_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24096,7 +26021,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capabi
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_both_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_default_originate_route_map_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -24111,11 +26036,51 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capabi
        return NB_OK;
 }
 
+static int bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+       int direction;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "unnumbered-neighbor");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
+       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
+                                                  args->errmsg_len);
+       if (!peer)
+               return NB_ERR_INCONSISTENCY;
+
+       direction = yang_dnode_get_enum(args->dnode, "./direction");
+
+       switch (direction) {
+       case 1:
+               peer_maximum_prefix_unset(peer, afi, safi);
+               break;
+       case 2:
+               UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT);
+               peer->pmax_out[afi][safi] = 0;
+               break;
+       }
+
+       return NB_OK;
+}
+
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_create(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_create(
        struct nb_cb_create_args *args)
 {
        switch (args->event) {
@@ -24130,7 +26095,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -24146,15 +26111,42 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/max-prefixes
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_max_prefixes_modify(
-       struct nb_cb_modify_args *args)
+void bgp_unnumbered_neighbor_afi_safi_prefix_limit_apply_finish(
+       struct nb_cb_apply_finish_args *args)
 {
-       switch (args->event) {
-       case NB_EV_VALIDATE:
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "unnumbered-neighbor");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
+       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
+                                                  args->errmsg_len);
+       if (!peer)
+               return;
+
+       bgp_peer_afi_safi_maximum_prefix_set(args, peer, afi, safi);
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/max-prefixes
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_max_prefixes_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
        case NB_EV_APPLY:
@@ -24167,9 +26159,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/force-check
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/force-check
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_force_check_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_force_check_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24186,9 +26178,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/warning-only
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24203,7 +26195,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -24220,9 +26212,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/restart-timer
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24237,7 +26229,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -24254,9 +26246,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24271,7 +26263,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -24288,9 +26280,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24305,7 +26297,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -24322,9 +26314,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tr-restart-timer
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24339,7 +26331,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -24356,9 +26348,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24373,7 +26365,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -24390,9 +26382,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tw-warning-only
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24407,7 +26399,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -24424,9 +26416,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_lim
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/nexthop-self/next-hop-self
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_nexthop_self_next_hop_self_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_nexthop_self_next_hop_self_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24447,9 +26439,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_nexthop_se
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/nexthop-self/next-hop-self-force
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/nexthop-self/next-hop-self-force
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_nexthop_self_next_hop_self_force_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_nexthop_self_next_hop_self_force_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24470,9 +26462,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_nexthop_se
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as-all
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_all_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_all_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24493,9 +26485,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_private_as
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as-all-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as-all-replace
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_all_replace_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_all_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24516,9 +26508,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_private_as
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24539,9 +26531,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_private_as
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as-replace
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_replace_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24560,11 +26552,111 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_private_as
        return NB_OK;
 }
 
+static int
+bgp_unnumbered_neighbor_afi_safi_weight_modify(struct nb_cb_modify_args *args)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const char *af_name;
+       uint16_t weight;
+       afi_t afi;
+       safi_t safi;
+       const struct lyd_node *nbr_af_dnode;
+       int ret;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "unnumbered-neighbor");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
+       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
+                                                  args->errmsg_len);
+
+       weight = yang_dnode_get_uint16(args->dnode, NULL);
+
+       ret = peer_weight_set(peer, afi, safi, weight);
+       if (bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret) < 0)
+               return NB_ERR_INCONSISTENCY;
+
+       return NB_OK;
+}
+
+static int
+bgp_unnumbered_neighbor_afi_safi_weight_destroy(struct nb_cb_destroy_args *args)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+       int ret;
+
+       bgp = nb_running_get_entry(args->dnode, NULL, true);
+       nbr_dnode = yang_dnode_get_parent(args->dnode, "unnumbered-neighbor");
+       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
+       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
+                                                  args->errmsg_len);
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       ret = peer_weight_unset(peer, afi, safi);
+       if (bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret) < 0)
+               return NB_ERR_INCONSISTENCY;
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/weight/weight-attribute
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_weight_weight_attribute_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_weight_modify(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_weight_weight_attribute_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_weight_destroy(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/route-reflector/route-reflector-client
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_route_reflector_route_reflector_client_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24585,9 +26677,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_route_refl
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/route-server/route-server-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/route-server/route-server-client
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_route_server_route_server_client_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24608,9 +26700,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_route_serv
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/send-community/send-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/send-community/send-community
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_send_community_send_community_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_send_community_send_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24631,9 +26723,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_send_commu
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/send-community/send-ext-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/send-community/send-ext-community
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_send_community_send_ext_community_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_send_community_send_ext_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24654,9 +26746,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_send_commu
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/send-community/send-large-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/send-community/send-large-community
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_send_community_send_large_community_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_send_community_send_large_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24677,9 +26769,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_send_commu
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/soft-reconfiguration
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_soft_reconfiguration_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24700,9 +26792,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_soft_recon
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/attr-unchanged/as-path-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_attr_unchanged_as_path_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24711,7 +26803,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_wei
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_weight_modify(args);
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
 
                break;
        }
@@ -24719,8 +26813,12 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_wei
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/attr-unchanged/next-hop-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_attr_unchanged_next_hop_unchanged_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -24728,7 +26826,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_wei
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_weight_destroy(args);
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
 
                break;
        }
@@ -24738,17 +26838,21 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_wei
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/add-paths/path-type
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/attr-unchanged/med-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_add_paths_path_type_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_attr_unchanged_med_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_MED_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -24757,9 +26861,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_add_path
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/orf-capability/orf-send
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_send_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24774,7 +26878,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_as_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_send_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -24791,9 +26895,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/orf-capability/orf-receive
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_origin_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_receive_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -24808,7 +26912,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_origin_as_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_receive_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -24825,33 +26929,25 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/orf-capability/orf-both
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_options_replace_peer_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_both_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_OVERRIDE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/default-originate/originate
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_default_originate_originate_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_both_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -24865,35 +26961,99 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_default_
        return NB_OK;
 }
 
+static int
+bgp_unnumbered_neighbor_afi_safi_rmap_modify(struct nb_cb_modify_args *args,
+                                            int direct)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+       const char *name_str;
+       struct route_map *route_map;
+       int ret;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "unnumbered-neighbor");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
+       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
+                                                  args->errmsg_len);
+
+       name_str = yang_dnode_get_string(args->dnode, NULL);
+       route_map = route_map_lookup_by_name(name_str);
+       ret = peer_route_map_set(peer, afi, safi, direct, name_str, route_map);
+
+       return bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret);
+}
+
+static int
+bgp_unnumbered_neighbor_afi_safi_rmap_destroy(struct nb_cb_destroy_args *args,
+                                             int direct)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+       int ret;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "unnumbered-neighbor");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
+       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
+                                                  args->errmsg_len);
+
+       ret = peer_route_map_unset(peer, afi, safi, direct);
+
+       return bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret);
+}
+
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/default-originate/route-map
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/rmap-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_default_originate_route_map_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args,
+                                                                   RMAP_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_default_originate_route_map_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args,
+                                                                    RMAP_IN);
        }
 
        return NB_OK;
@@ -24901,102 +27061,130 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_default_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/attr-unchanged/as-path-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/rmap-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_as_path_unchanged_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args,
+                                                                   RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/attr-unchanged/next-hop-unchanged
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_next_hop_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args,
+                                                                    RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/attr-unchanged/med-unchanged
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_med_unchanged_modify(
-       struct nb_cb_modify_args *args)
+static int
+bgp_unnumbered_neighbor_afi_safi_plist_modify(struct nb_cb_modify_args *args,
+                                             int direct)
 {
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+       const char *name_str;
 
-               break;
-       }
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "unnumbered-neighbor");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
+       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
+                                                  args->errmsg_len);
+
+       name_str = yang_dnode_get_string(args->dnode, NULL);
+       if (peer_prefix_list_set(peer, afi, safi, direct, name_str) < 0)
+               return NB_ERR_INCONSISTENCY;
 
        return NB_OK;
 }
 
+static int
+bgp_unnumbered_neighbor_afi_safi_plist_destroy(struct nb_cb_destroy_args *args,
+                                              int direct)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "unnumbered-neighbor");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./interface");
+       peer = bgp_unnumbered_neighbor_peer_lookup(bgp, peer_str, args->errmsg,
+                                                  args->errmsg_len);
+
+       if (peer_prefix_list_unset(peer, afi, safi, direct) < 0)
+               return NB_ERR_INCONSISTENCY;
+
+       return NB_OK;
+}
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/orf-capability/orf-send
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/plist-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_send_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_modify(args,
+                                                                    FILTER_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_send_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_destroy(
+                       args, FILTER_IN);
        }
 
        return NB_OK;
@@ -25004,33 +27192,35 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capa
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/orf-capability/orf-receive
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/plist-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_receive_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_modify(
+                       args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_receive_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_destroy(
+                       args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -25038,9 +27228,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capa
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/orf-capability/orf-both
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/access-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_both_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25055,7 +27245,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capa
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_both_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -25072,10 +27262,10 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capa
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/access-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_create(
-       struct nb_cb_create_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -25089,17 +27279,16 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
-                       args);
+               /* TODO: implement me. */
+               break;
        }
 
        return NB_OK;
@@ -25107,9 +27296,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/as-path-filter-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25124,12 +27313,8 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/force-check
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_force_check_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -25145,9 +27330,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/as-path-filter-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25162,7 +27347,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_warning_only_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -25179,9 +27364,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/unsuppress-map-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25196,7 +27381,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_restart_timer_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -25213,9 +27398,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/filter-config/unsuppress-map-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25230,7 +27415,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -25247,9 +27432,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/nexthop-local-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_nexthop_local_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25264,8 +27449,12 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/add-paths/path-type
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_add_paths_path_type_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -25281,9 +27470,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/as-path-options/allow-own-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25298,7 +27487,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -25315,9 +27504,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/as-path-options/allow-own-origin-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_origin_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25332,7 +27521,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_origin_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -25349,25 +27538,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/as-path-options/replace-peer-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_as_path_options_replace_peer_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_OVERRIDE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/default-originate/originate
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_default_originate_originate_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -25383,21 +27580,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/default-originate/route-map
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_nexthop_self_next_hop_self_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_default_originate_route_map_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
 
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_default_originate_route_map_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -25406,9 +27614,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_nexthop_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/nexthop-self/next-hop-self-force
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/attr-unchanged/as-path-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_nexthop_self_next_hop_self_force_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_attr_unchanged_as_path_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25418,7 +27626,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_nexthop_
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -25429,9 +27637,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_nexthop_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/attr-unchanged/next-hop-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_all_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_attr_unchanged_next_hop_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25441,7 +27649,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_private_
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -25452,9 +27660,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_private_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as-all-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/attr-unchanged/med-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_all_replace_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_attr_unchanged_med_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25464,7 +27672,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_private_
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+                       args, PEER_FLAG_MED_UNCHANGED,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -25475,21 +27683,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_private_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/orf-capability/orf-send
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_send_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
 
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_send_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -25498,21 +27717,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_private_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/orf-capability/orf-receive
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_replace_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_receive_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
 
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_receive_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -25521,21 +27751,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_private_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/orf-capability/orf-both
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_route_reflector_route_reflector_client_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_both_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
 
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_both_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -25544,33 +27785,25 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_route_re
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/route-server/route-server-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_route_server_route_server_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_create(
+       struct nb_cb_create_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/send-community/send-community
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_send_community_send_community_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -25578,11 +27811,8 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_send_com
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
+               return bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
+                       args);
        }
 
        return NB_OK;
@@ -25590,21 +27820,17 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_send_com
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/send-community/send-ext-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/max-prefixes
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_send_community_send_ext_community_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_max_prefixes_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -25613,21 +27839,17 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_send_com
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/send-community/send-large-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/force-check
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_send_community_send_large_community_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_force_check_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -25636,21 +27858,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_send_com
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/warning-only
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_soft_reconfiguration_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
 
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -25659,36 +27892,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_soft_rec
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/restart-timer
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_weight_weight_attribute_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_weight_modify(args);
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_weight_weight_attribute_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_weight_destroy(args);
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -25697,9 +27926,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_weight_w
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/add-paths/path-type
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_add_paths_path_type_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25714,11 +27943,26 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_add_path
        return NB_OK;
 }
 
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25733,7 +27977,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_as_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -25750,9 +27994,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tr-restart-timer
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_origin_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25767,7 +28011,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_origin_as_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -25784,33 +28028,25 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_options_replace_peer_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_OVERRIDE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/default-originate/originate
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_default_originate_originate_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -25826,9 +28062,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_default_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/default-originate/route-map
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tw-warning-only
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_default_originate_route_map_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25843,7 +28079,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_default_
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_default_originate_route_map_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -25860,9 +28096,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_default_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/attr-unchanged/as-path-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/nexthop-self/next-hop-self
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_attr_unchanged_as_path_unchanged_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_nexthop_self_next_hop_self_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25872,7 +28108,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_attr_unc
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
+                       args, PEER_FLAG_NEXTHOP_SELF,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -25883,9 +28119,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_attr_unc
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/attr-unchanged/next-hop-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/nexthop-self/next-hop-self-force
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_attr_unchanged_next_hop_unchanged_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_nexthop_self_next_hop_self_force_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25895,7 +28131,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_attr_unc
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -25906,9 +28142,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_attr_unc
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/attr-unchanged/med-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as-all
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_attr_unchanged_med_unchanged_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_all_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -25918,7 +28154,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_attr_unc
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -25929,32 +28165,44 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_attr_unc
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/orf-capability/orf-send
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as-all-replace
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_send_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_all_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_send_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -25963,32 +28211,44 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capa
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/orf-capability/orf-receive
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as-replace
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_receive_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_receive_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/route-reflector/route-reflector-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_route_reflector_route_reflector_client_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -25997,32 +28257,44 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capa
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/orf-capability/orf-both
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/route-server/route-server-client
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_both_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_both_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/send-community/send-community
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_send_community_send_community_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -26031,25 +28303,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capa
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/send-community/send-ext-community
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_create(
-       struct nb_cb_create_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_send_community_send_ext_community_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/send-community/send-large-community
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_send_community_send_large_community_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -26057,8 +28337,11 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_l
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
-                       args);
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
        }
 
        return NB_OK;
@@ -26066,17 +28349,21 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/soft-reconfiguration
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -26085,17 +28372,36 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/force-check
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/weight/weight-attribute
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_force_check_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_weight_modify(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_weight_destroy(args);
+
                break;
        }
 
@@ -26104,33 +28410,35 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/rmap-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args,
+                                                                   RMAP_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_warning_only_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args,
+                                                                    RMAP_IN);
        }
 
        return NB_OK;
@@ -26138,33 +28446,35 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/rmap-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args,
+                                                                   RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_restart_timer_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args,
+                                                                    RMAP_OUT);
        }
 
        return NB_OK;
@@ -26172,33 +28482,35 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/plist-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_modify(args,
+                                                                    FILTER_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_destroy(
+                       args, FILTER_IN);
        }
 
        return NB_OK;
@@ -26206,33 +28518,35 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/plist-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_modify(
+                       args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_destroy(
+                       args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -26240,9 +28554,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/access-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26257,7 +28571,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_l
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -26274,9 +28588,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/access-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26291,7 +28605,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_l
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -26308,9 +28622,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/as-path-filter-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26325,7 +28639,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_l
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -26342,44 +28656,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_l
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/as-path-filter-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_nexthop_self_next_hop_self_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/nexthop-self/next-hop-self-force
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_nexthop_self_next_hop_self_force_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -26388,228 +28690,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_nexthop_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/unsuppress-map-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_all_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
-       }
-
-       return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as-all-replace
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_all_replace_modify(
-       struct nb_cb_modify_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
-       }
-
-       return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_modify(
-       struct nb_cb_modify_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
-       }
-
-       return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as-replace
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_replace_modify(
-       struct nb_cb_modify_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
-       }
-
-       return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/route-reflector/route-reflector-client
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_route_reflector_route_reflector_client_modify(
-       struct nb_cb_modify_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
-       }
-
-       return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/route-server/route-server-client
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_route_server_route_server_client_modify(
-       struct nb_cb_modify_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
-       }
-
-       return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/send-community/send-community
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_send_community_send_community_modify(
-       struct nb_cb_modify_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
-       }
-
-       return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/send-community/send-ext-community
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_send_community_send_ext_community_modify(
-       struct nb_cb_modify_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
-       }
-
-       return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/send-community/send-large-community
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_send_community_send_large_community_modify(
-       struct nb_cb_modify_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/soft-reconfiguration
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_soft_reconfiguration_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -26618,36 +28724,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_soft_rec
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast/filter-config/unsuppress-map-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_weight_weight_attribute_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_weight_modify(args);
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_weight_weight_attribute_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_weight_destroy(args);
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -26656,9 +28758,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_weight_w
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/add-paths/path-type
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/add-paths/path-type
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_add_paths_path_type_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26675,9 +28777,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_ad
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/as-path-options/allow-own-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26692,7 +28794,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -26709,9 +28811,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/as-path-options/allow-own-origin-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_origin_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_origin_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26726,7 +28828,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_origin_as_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_origin_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -26743,9 +28845,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/as-path-options/replace-peer-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_replace_peer_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_as_path_options_replace_peer_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26766,9 +28868,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/default-originate/originate
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/default-originate/originate
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_default_originate_originate_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_default_originate_originate_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26785,9 +28887,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_de
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/default-originate/route-map
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/default-originate/route-map
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_default_originate_route_map_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_default_originate_route_map_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26802,7 +28904,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_de
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_default_originate_route_map_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_default_originate_route_map_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -26819,9 +28921,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_de
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/attr-unchanged/as-path-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/attr-unchanged/as-path-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unchanged_as_path_unchanged_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_as_path_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26842,9 +28944,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_at
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/attr-unchanged/next-hop-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/attr-unchanged/next-hop-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unchanged_next_hop_unchanged_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_next_hop_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26865,9 +28967,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_at
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/attr-unchanged/med-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/attr-unchanged/med-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unchanged_med_unchanged_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_med_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26888,9 +28990,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_at
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/orf-capability/orf-send
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/orf-capability/orf-send
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_send_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_send_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26905,7 +29007,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_or
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_send_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_send_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -26922,9 +29024,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_or
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/orf-capability/orf-receive
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/orf-capability/orf-receive
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_receive_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_receive_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26939,7 +29041,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_or
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_receive_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_receive_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -26956,9 +29058,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_or
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/orf-capability/orf-both
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/orf-capability/orf-both
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_both_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_both_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -26973,7 +29075,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_or
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_both_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_both_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -26990,9 +29092,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_or
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_create(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_create(
        struct nb_cb_create_args *args)
 {
        switch (args->event) {
@@ -27007,7 +29109,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -27025,9 +29127,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/max-prefixes
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_max_prefixes_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27044,9 +29146,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/force-check
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/force-check
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_force_check_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_force_check_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27063,9 +29165,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/warning-only
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27080,7 +29182,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -27097,9 +29199,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/restart-timer
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27114,7 +29216,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_restart_timer_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -27131,9 +29233,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27148,7 +29250,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -27165,9 +29267,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27182,7 +29284,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -27199,9 +29301,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tr-restart-timer
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27216,7 +29318,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -27233,9 +29335,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27250,7 +29352,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -27267,9 +29369,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tw-warning-only
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27284,7 +29386,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -27301,9 +29403,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/nexthop-self/next-hop-self
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_nexthop_self_next_hop_self_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_nexthop_self_next_hop_self_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27324,9 +29426,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_ne
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/nexthop-self/next-hop-self-force
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/nexthop-self/next-hop-self-force
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_nexthop_self_next_hop_self_force_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_nexthop_self_next_hop_self_force_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27347,9 +29449,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_ne
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as-all
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_all_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_all_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27370,9 +29472,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as-all-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as-all-replace
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_all_replace_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_all_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27393,9 +29495,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27416,9 +29518,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as-replace
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_replace_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27439,9 +29541,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/route-reflector/route-reflector-client
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_route_reflector_route_reflector_client_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27462,9 +29564,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_ro
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/route-server/route-server-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/route-server/route-server-client
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_route_server_route_server_client_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27485,9 +29587,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_ro
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/send-community/send-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/send-community/send-community
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_send_community_send_community_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_send_community_send_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27508,9 +29610,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_se
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/send-community/send-ext-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/send-community/send-ext-community
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_send_community_send_ext_community_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_send_community_send_ext_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27531,9 +29633,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_se
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/send-community/send-large-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/send-community/send-large-community
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_send_community_send_large_community_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_send_community_send_large_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27554,9 +29656,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_se
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/soft-reconfiguration
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_soft_reconfiguration_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27577,9 +29679,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_so
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/weight/weight-attribute
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight_attribute_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_weight_weight_attribute_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27596,7 +29698,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_we
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight_attribute_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -27615,18 +29717,35 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_we
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/add-paths/path-type
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/rmap-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_add_paths_path_type_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               break;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args,
+                                                                   RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_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 bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args,
+                                                                    RMAP_IN);
        }
 
        return NB_OK;
@@ -27634,33 +29753,35 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_ad
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/rmap-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args,
+                                                                   RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_as_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args,
+                                                                    RMAP_OUT);
        }
 
        return NB_OK;
@@ -27668,33 +29789,35 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_as
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/plist-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_origin_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_modify(args,
+                                                                    FILTER_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_origin_as_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_destroy(
+                       args, FILTER_IN);
        }
 
        return NB_OK;
@@ -27702,41 +29825,35 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_as
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/plist-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_replace_peer_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_OVERRIDE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_modify(
+                       args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/default-originate/originate
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_default_originate_originate_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_destroy(
+                       args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -27744,9 +29861,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_de
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/default-originate/route-map
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/access-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_default_originate_route_map_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27761,7 +29878,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_de
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_default_originate_route_map_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -27778,67 +29895,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_de
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/attr-unchanged/as-path-unchanged
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_attr_unchanged_as_path_unchanged_modify(
-       struct nb_cb_modify_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
-       }
-
-       return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/attr-unchanged/next-hop-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/access-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_attr_unchanged_next_hop_unchanged_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/attr-unchanged/med-unchanged
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_attr_unchanged_med_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -27847,9 +29929,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_at
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/orf-capability/orf-send
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/as-path-filter-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_send_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27864,7 +29946,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_or
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_send_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -27881,9 +29963,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_or
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/orf-capability/orf-receive
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/as-path-filter-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_receive_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27898,7 +29980,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_or
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_receive_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -27915,9 +29997,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_or
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/orf-capability/orf-both
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/unsuppress-map-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_both_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -27932,7 +30014,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_or
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_both_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -27949,10 +30031,10 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_or
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast/filter-config/unsuppress-map-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_create(
-       struct nb_cb_create_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -27966,17 +30048,16 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
-                       args);
+               /* TODO: implement me. */
+               break;
        }
 
        return NB_OK;
@@ -27984,9 +30065,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/add-paths/path-type
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28003,9 +30084,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/force-check
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/as-path-options/allow-own-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_force_check_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28020,11 +30101,26 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/warning-only
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_as_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/as-path-options/allow-own-origin-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_origin_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28039,7 +30135,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_origin_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -28056,25 +30152,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/as-path-options/replace-peer-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_as_path_options_replace_peer_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_OVERRIDE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/default-originate/originate
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_default_originate_originate_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -28090,9 +30194,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/default-originate/route-map
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_default_originate_route_map_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28107,7 +30211,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_default_originate_route_map_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -28124,32 +30228,44 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/attr-unchanged/as-path-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_attr_unchanged_as_path_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/attr-unchanged/next-hop-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_attr_unchanged_next_hop_unchanged_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -28158,9 +30274,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/attr-unchanged/med-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_attr_unchanged_med_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_MED_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/orf-capability/orf-send
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_send_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28175,7 +30314,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_send_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -28192,9 +30331,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/orf-capability/orf-receive
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_receive_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28209,7 +30348,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_receive_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -28226,9 +30365,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/orf-capability/orf-both
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_both_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28243,7 +30382,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_both_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -28260,33 +30399,25 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_nexthop_self_next_hop_self_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_create(
+       struct nb_cb_create_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/nexthop-self/next-hop-self-force
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_nexthop_self_next_hop_self_force_modify(
-       struct nb_cb_modify_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -28294,11 +30425,8 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_ne
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
+               return bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
+                       args);
        }
 
        return NB_OK;
@@ -28306,21 +30434,17 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_ne
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/max-prefixes
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_all_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_max_prefixes_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -28329,21 +30453,17 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as-all-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/force-check
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_all_replace_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_force_check_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -28352,21 +30472,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/warning-only
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
 
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -28375,21 +30506,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/restart-timer
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_replace_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
 
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -28398,21 +30540,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_pr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_route_reflector_route_reflector_client_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
 
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -28421,21 +30574,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_ro
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/route-server/route-server-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_route_server_route_server_client_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
 
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -28444,21 +30608,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_ro
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/send-community/send-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tr-restart-timer
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_send_community_send_community_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
 
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -28467,21 +30642,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_se
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/send-community/send-ext-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_send_community_send_ext_community_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
 
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -28490,21 +30676,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_se
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/send-community/send-large-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tw-warning-only
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_send_community_send_large_community_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
 
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -28513,9 +30710,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_se
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/nexthop-self/next-hop-self
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_soft_reconfiguration_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_nexthop_self_next_hop_self_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28525,7 +30722,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_so
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
+                       args, PEER_FLAG_NEXTHOP_SELF,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -28536,9 +30733,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_so
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/nexthop-self/next-hop-self-force
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_weight_weight_attribute_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_nexthop_self_next_hop_self_force_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28547,7 +30744,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_we
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_weight_modify(args);
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
 
                break;
        }
@@ -28555,8 +30754,12 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_we
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_weight_weight_attribute_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as-all
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_all_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -28564,7 +30767,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_we
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_weight_destroy(args);
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+                       yang_dnode_get_bool(args->dnode, NULL));
 
                break;
        }
@@ -28574,17 +30779,21 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_we
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/add-paths/path-type
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as-all-replace
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_add_paths_path_type_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_all_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -28593,32 +30802,44 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_add_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_as_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as-replace
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_replace_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -28627,32 +30848,44 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_p
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/route-reflector/route-reflector-client
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_origin_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_origin_as_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/route-server/route-server-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_route_server_route_server_client_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -28661,9 +30894,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_p
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/send-community/send-community
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_replace_peer_as_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_send_community_send_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28673,7 +30906,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_p
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_OVERRIDE,
+                       args, PEER_FLAG_SEND_COMMUNITY,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -28684,9 +30917,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_p
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/attr-unchanged/as-path-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/send-community/send-ext-community
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchanged_as_path_unchanged_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_send_community_send_ext_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28696,7 +30929,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
+                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -28707,9 +30940,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/attr-unchanged/next-hop-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/send-community/send-large-community
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchanged_next_hop_unchanged_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_send_community_send_large_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28719,7 +30952,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
+                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -28730,9 +30963,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/attr-unchanged/med-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/soft-reconfiguration
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchanged_med_unchanged_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28742,7 +30975,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
+                       args, PEER_FLAG_SOFT_RECONFIG,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -28753,24 +30986,26 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/weight/weight-attribute
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_create(
-       struct nb_cb_create_args *args)
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_weight_weight_attribute_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_weight_modify(args);
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -28779,8 +31014,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
-                       args);
+               return bgp_unnumbered_neighbor_afi_safi_weight_destroy(args);
+
+               break;
        }
 
        return NB_OK;
@@ -28788,18 +31024,35 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/rmap-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               break;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args,
+                                                                   RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_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 bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args,
+                                                                    RMAP_IN);
        }
 
        return NB_OK;
@@ -28807,18 +31060,35 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/force-check
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/rmap-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_force_check_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               break;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args,
+                                                                   RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_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 bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args,
+                                                                    RMAP_OUT);
        }
 
        return NB_OK;
@@ -28826,33 +31096,35 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/plist-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_modify(args,
+                                                                    FILTER_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_destroy(
+                       args, FILTER_IN);
        }
 
        return NB_OK;
@@ -28860,33 +31132,35 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/plist-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_modify(
+                       args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_destroy(
+                       args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -28894,9 +31168,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/access-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28911,7 +31185,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -28928,9 +31202,6790 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/access-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/as-path-filter-list-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/as-path-filter-list-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/unsuppress-map-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast/filter-config/unsuppress-map-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/add-paths/path-type
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_add_paths_path_type_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/allow-own-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/allow-own-origin-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_origin_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_origin_as_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/replace-peer-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_replace_peer_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_OVERRIDE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/default-originate/originate
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_default_originate_originate_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/default-originate/route-map
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_default_originate_route_map_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_default_originate_route_map_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/attr-unchanged/as-path-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unchanged_as_path_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/attr-unchanged/next-hop-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unchanged_next_hop_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/attr-unchanged/med-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unchanged_med_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_MED_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/orf-capability/orf-send
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_send_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_send_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/orf-capability/orf-receive
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_receive_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_receive_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/orf-capability/orf-both
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_both_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_both_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_create(
+       struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
+                       args);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/max-prefixes
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_max_prefixes_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/force-check
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_force_check_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/warning-only
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_warning_only_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/restart-timer
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tw-warning-only
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/nexthop-self/next-hop-self
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_nexthop_self_next_hop_self_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/nexthop-self/next-hop-self-force
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_nexthop_self_next_hop_self_force_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as-all
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_all_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as-all-replace
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_all_replace_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as-replace
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_replace_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/route-reflector/route-reflector-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_route_reflector_route_reflector_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/route-server/route-server-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_route_server_route_server_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/send-community/send-community
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_send_community_send_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/send-community/send-ext-community
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_send_community_send_ext_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/send-community/send-large-community
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_send_community_send_large_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/soft-reconfiguration
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_soft_reconfiguration_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/weight/weight-attribute
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight_attribute_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_weight_modify(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight_attribute_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_weight_destroy(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/rmap-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args,
+                                                                   RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_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 bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args,
+                                                                    RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/rmap-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args,
+                                                                   RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_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 bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args,
+                                                                    RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/plist-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_modify(args,
+                                                                    FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_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 bgp_unnumbered_neighbor_afi_safi_plist_destroy(
+                       args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/plist-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_modify(
+                       args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_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 bgp_unnumbered_neighbor_afi_safi_plist_destroy(
+                       args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/access-list-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/access-list-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/as-path-filter-list-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/as-path-filter-list-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/unsuppress-map-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/unsuppress-map-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/add-paths/path-type
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_add_paths_path_type_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/as-path-options/allow-own-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_as_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/as-path-options/allow-own-origin-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_origin_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_origin_as_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/as-path-options/replace-peer-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_replace_peer_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_OVERRIDE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/default-originate/originate
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_default_originate_originate_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/default-originate/route-map
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_default_originate_route_map_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_default_originate_route_map_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/attr-unchanged/as-path-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_attr_unchanged_as_path_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/attr-unchanged/next-hop-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_attr_unchanged_next_hop_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/attr-unchanged/med-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_attr_unchanged_med_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_MED_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/orf-capability/orf-send
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_send_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_send_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/orf-capability/orf-receive
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_receive_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_receive_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/orf-capability/orf-both
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_both_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_both_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_create(
+       struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
+                       args);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/max-prefixes
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_max_prefixes_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/force-check
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_force_check_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/warning-only
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_warning_only_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/restart-timer
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tw-warning-only
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/nexthop-self/next-hop-self
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_nexthop_self_next_hop_self_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/nexthop-self/next-hop-self-force
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_nexthop_self_next_hop_self_force_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as-all
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_all_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as-all-replace
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_all_replace_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as-replace
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_replace_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/route-reflector/route-reflector-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_route_reflector_route_reflector_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/route-server/route-server-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_route_server_route_server_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/send-community/send-community
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_send_community_send_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/send-community/send-ext-community
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_send_community_send_ext_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/send-community/send-large-community
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_send_community_send_large_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/soft-reconfiguration
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_soft_reconfiguration_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast/weight/weight-attribute
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_weight_weight_attribute_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_weight_modify(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_weight_weight_attribute_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_weight_destroy(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/add-paths/path-type
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_add_paths_path_type_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/as-path-options/allow-own-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_as_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/as-path-options/allow-own-origin-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_origin_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_origin_as_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/as-path-options/replace-peer-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_replace_peer_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_OVERRIDE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/attr-unchanged/as-path-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchanged_as_path_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/attr-unchanged/next-hop-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchanged_next_hop_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/attr-unchanged/med-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchanged_med_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_MED_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_create(
+       struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
+                       args);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/max-prefixes
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_max_prefixes_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/force-check
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_force_check_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/warning-only
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_warning_only_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/restart-timer
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tw-warning-only
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/nexthop-self/next-hop-self
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_nexthop_self_next_hop_self_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/nexthop-self/next-hop-self-force
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_nexthop_self_next_hop_self_force_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as-all
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_all_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as-all-replace
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_all_replace_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as-replace
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_replace_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/route-reflector/route-reflector-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_route_reflector_route_reflector_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/route-server/route-server-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_route_server_route_server_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/send-community/send-community
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_community_send_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/send-community/send-ext-community
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_community_send_ext_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/send-community/send-large-community
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_community_send_large_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/soft-reconfiguration
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_soft_reconfiguration_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/weight/weight-attribute
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weight_attribute_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_weight_modify(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weight_attribute_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_weight_destroy(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/add-paths/path-type
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_add_paths_path_type_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/as-path-options/allow-own-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_as_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/as-path-options/allow-own-origin-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_origin_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_origin_as_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/as-path-options/replace-peer-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_replace_peer_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_OVERRIDE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/attr-unchanged/as-path-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchanged_as_path_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/attr-unchanged/next-hop-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchanged_next_hop_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/attr-unchanged/med-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchanged_med_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_MED_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_create(
+       struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
+                       args);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/max-prefixes
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_max_prefixes_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/force-check
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_force_check_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/warning-only
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_warning_only_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/restart-timer
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tw-warning-only
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/nexthop-self/next-hop-self
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_nexthop_self_next_hop_self_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/nexthop-self/next-hop-self-force
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_nexthop_self_next_hop_self_force_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as-all
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_all_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as-all-replace
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_all_replace_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as-replace
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_replace_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/route-reflector/route-reflector-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_route_reflector_route_reflector_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/route-server/route-server-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_route_server_route_server_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/send-community/send-community
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_community_send_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/send-community/send-ext-community
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_community_send_ext_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/send-community/send-large-community
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_community_send_large_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/soft-reconfiguration
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_soft_reconfiguration_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/weight/weight-attribute
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weight_attribute_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_weight_modify(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weight_attribute_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_weight_destroy(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-origin-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/replace-peer-as
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_replace_peer_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_OVERRIDE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/as-path-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_as_path_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/next-hop-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_next_hop_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/med-unchanged
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_med_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_MED_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/nexthop-self/next-hop-self
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_nexthop_self_next_hop_self_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/nexthop-self/next-hop-self-force
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_nexthop_self_next_hop_self_force_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/route-reflector/route-reflector-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_route_reflector_route_reflector_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/route-server/route-server-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_route_server_route_server_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/soft-reconfiguration
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_soft_reconfiguration_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/route-reflector/route-reflector-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_reflector_route_reflector_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/route-server/route-server-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_server_route_server_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/soft-reconfiguration
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_soft_reconfiguration_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/rmap-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args,
+                                                                   RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_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 bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args,
+                                                                    RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/rmap-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args,
+                                                                   RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_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 bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args,
+                                                                    RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/plist-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_modify(args,
+                                                                    FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_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 bgp_unnumbered_neighbor_afi_safi_plist_destroy(
+                       args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/plist-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_modify(
+                       args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_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 bgp_unnumbered_neighbor_afi_safi_plist_destroy(
+                       args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/access-list-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/access-list-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/as-path-filter-list-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/as-path-filter-list-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/unsuppress-map-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/filter-config/unsuppress-map-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/route-reflector/route-reflector-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_route_reflector_route_reflector_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/route-server/route-server-client
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_route_server_route_server_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/soft-reconfiguration
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_soft_reconfiguration_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/rmap-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args,
+                                                                   RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_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 bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args,
+                                                                    RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/rmap-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args,
+                                                                   RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_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 bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args,
+                                                                    RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/plist-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_modify(args,
+                                                                    FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_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 bgp_unnumbered_neighbor_afi_safi_plist_destroy(
+                       args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/plist-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_unnumbered_neighbor_afi_safi_plist_modify(
+                       args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_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 bgp_unnumbered_neighbor_afi_safi_plist_destroy(
+                       args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/access-list-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/access-list-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/as-path-filter-list-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/as-path-filter-list-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/unsuppress-map-import
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/filter-config/unsuppress-map-export
+ */
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+static int bgp_peer_group_afi_safi_flag_modify(struct nb_cb_modify_args *args,
+                                              uint32_t flags, bool set)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "peer-group");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
+       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
+
+       if (peer_af_flag_modify_nb(peer, afi, safi, flags, set, args->errmsg,
+                                  args->errmsg_len)
+           < 0)
+               return NB_ERR_INCONSISTENCY;
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/add-paths/path-type
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_add_paths_path_type_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/as-path-options/allow-own-as
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_as_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/as-path-options/allow-own-origin-as
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_origin_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_origin_as_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/as-path-options/replace-peer-as
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_replace_peer_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_OVERRIDE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/default-originate
+ */
+void bgp_peer_group_afi_safi_default_originate_apply_finish(
+       struct nb_cb_apply_finish_args *args)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "peer-group");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
+       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
+       if (!peer)
+               return;
+
+       bgp_peer_afi_safi_default_originate_apply(args, peer, afi, safi);
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/default-originate/originate
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_default_originate_originate_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/default-originate/route-map
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_default_originate_route_map_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_default_originate_route_map_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+static int bgp_peer_group_afi_safi_prefix_limit_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+       int direction;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "peer-group");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
+       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
+       if (!peer)
+               return NB_ERR_INCONSISTENCY;
+
+       direction = yang_dnode_get_enum(args->dnode, "./direction");
+
+       switch (direction) {
+       case 1:
+               peer_maximum_prefix_unset(peer, afi, safi);
+               break;
+       case 2:
+               UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT);
+               peer->pmax_out[afi][safi] = 0;
+               break;
+       }
+
+       return NB_OK;
+}
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_create(
+       struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_prefix_limit_list_destroy(args);
+       }
+
+       return NB_OK;
+}
+
+void bgp_peer_group_afi_safi_prefix_limit_apply_finish(
+       struct nb_cb_apply_finish_args *args)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "peer-group");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
+       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
+       if (!peer)
+               return;
+
+       bgp_peer_afi_safi_maximum_prefix_set(args, peer, afi, safi);
+}
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/max-prefixes
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_max_prefixes_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/force-check
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_force_check_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/warning-only
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_warning_only_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/restart-timer
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tw-warning-only
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/nexthop-self/next-hop-self
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_nexthop_self_next_hop_self_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/nexthop-self/next-hop-self-force
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_nexthop_self_next_hop_self_force_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as-all
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_all_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as-all-replace
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_all_replace_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as-replace
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_replace_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+static int bgp_peer_group_afi_safi_weight_modify(struct nb_cb_modify_args *args)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       uint16_t weight;
+       afi_t afi;
+       safi_t safi;
+       int ret;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+
+       nbr_dnode = yang_dnode_get_parent(args->dnode, "peer-group");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
+       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
+
+       weight = yang_dnode_get_uint16(args->dnode, NULL);
+
+       ret = peer_weight_set(peer, afi, safi, weight);
+       if (bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret) < 0)
+               return NB_ERR_INCONSISTENCY;
+
+       return NB_OK;
+}
+
+static int
+bgp_peer_group_afi_safi_weight_destroy(struct nb_cb_destroy_args *args)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+       int ret;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "peer-group");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
+       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
+
+       ret = peer_weight_unset(peer, afi, safi);
+       if (bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret) < 0)
+               return NB_ERR_INCONSISTENCY;
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/weight/weight-attribute
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_weight_weight_attribute_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_weight_modify(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_weight_weight_attribute_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_weight_destroy(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/route-reflector/route-reflector-client
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_route_reflector_route_reflector_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/route-server/route-server-client
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_route_server_route_server_client_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/send-community/send-community
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_send_community_send_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/send-community/send-ext-community
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_send_community_send_ext_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/send-community/send-large-community
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_send_community_send_large_community_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/soft-reconfiguration
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_soft_reconfiguration_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/attr-unchanged/as-path-unchanged
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_attr_unchanged_as_path_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/attr-unchanged/next-hop-unchanged
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_attr_unchanged_next_hop_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/attr-unchanged/med-unchanged
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_attr_unchanged_med_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_MED_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/orf-capability/orf-send
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_send_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_send_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/orf-capability/orf-receive
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_receive_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_receive_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/orf-capability/orf-both
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_both_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_both_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+static int bgp_peer_group_afi_safi_rmap_modify(struct nb_cb_modify_args *args,
+                                              int direct)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+       const char *name_str;
+       struct route_map *route_map;
+       int ret;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "peer-group");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
+       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
+
+       name_str = yang_dnode_get_string(args->dnode, NULL);
+       route_map = route_map_lookup_by_name(name_str);
+       ret = peer_route_map_set(peer, afi, safi, direct, name_str, route_map);
+
+       return bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret);
+}
+
+static int bgp_peer_group_afi_safi_rmap_destroy(struct nb_cb_destroy_args *args,
+                                               int direct)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+       int ret;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "peer-group");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
+       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
+
+       ret = peer_route_map_unset(peer, afi, safi, direct);
+
+       return bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret);
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/rmap-import
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_import_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 bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/rmap-export
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_export_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 bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+static int bgp_peer_group_afi_safi_plist_modify(struct nb_cb_modify_args *args,
+                                               int direct)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+       const char *name_str;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "peer-group");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
+       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
+
+       name_str = yang_dnode_get_string(args->dnode, NULL);
+       if (peer_prefix_list_set(peer, afi, safi, direct, name_str) < 0)
+               return NB_ERR_INCONSISTENCY;
+
+       return NB_OK;
+}
+
+static int
+bgp_peer_group_afi_safi_plist_destroy(struct nb_cb_destroy_args *args,
+                                     int direct)
+{
+       struct bgp *bgp;
+       const char *peer_str;
+       struct peer *peer;
+       const struct lyd_node *nbr_dnode;
+       const struct lyd_node *nbr_af_dnode;
+       const char *af_name;
+       afi_t afi;
+       safi_t safi;
+
+       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
+       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
+       yang_afi_safi_identity2value(af_name, &afi, &safi);
+       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "peer-group");
+       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
+       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
+       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
+
+       if (peer_prefix_list_unset(peer, afi, safi, direct) < 0)
+               return NB_ERR_INCONSISTENCY;
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/plist-import
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_import_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 bgp_peer_group_afi_safi_plist_destroy(args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/plist-export
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_export_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 bgp_peer_group_afi_safi_plist_destroy(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/access-list-import
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/access-list-export
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/as-path-filter-list-import
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/as-path-filter-list-export
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/unsuppress-map-import
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/unsuppress-map-export
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/nexthop-local-unchanged
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_nexthop_local_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/add-paths/path-type
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_add_paths_path_type_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/as-path-options/allow-own-as
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28945,7 +38000,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -28962,9 +38017,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/as-path-options/allow-own-origin-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_origin_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -28979,7 +38034,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_origin_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -28996,25 +38051,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/as-path-options/replace-peer-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_as_path_options_replace_peer_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_OVERRIDE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/default-originate/originate
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_default_originate_originate_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -29030,9 +38093,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/default-originate/route-map
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_default_originate_route_map_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -29047,7 +38110,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_default_originate_route_map_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -29064,9 +38127,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/attr-unchanged/as-path-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_nexthop_self_next_hop_self_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_attr_unchanged_as_path_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -29075,8 +38138,8 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_next
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -29087,9 +38150,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_next
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/nexthop-self/next-hop-self-force
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/attr-unchanged/next-hop-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_nexthop_self_next_hop_self_force_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_attr_unchanged_next_hop_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -29098,8 +38161,8 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_next
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -29110,9 +38173,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_next
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/attr-unchanged/med-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_all_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_attr_unchanged_med_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -29121,8 +38184,8 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_priv
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_MED_UNCHANGED,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -29133,44 +38196,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_priv
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as-all-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/orf-capability/orf-send
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_all_replace_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_send_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_send_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -29179,44 +38230,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_priv
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/orf-capability/orf-receive
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_replace_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_receive_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/route-reflector/route-reflector-client
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_route_reflector_route_reflector_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_receive_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -29225,21 +38264,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_rout
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/route-server/route-server-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/orf-capability/orf-both
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_route_server_route_server_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_both_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
 
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_both_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -29248,33 +38298,25 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_rout
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/send-community/send-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_community_send_community_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_create(
+       struct nb_cb_create_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/send-community/send-ext-community
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_community_send_ext_community_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -29282,11 +38324,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_send
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
+               return bgp_peer_group_afi_safi_prefix_limit_list_destroy(args);
        }
 
        return NB_OK;
@@ -29294,21 +38332,17 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_send
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/send-community/send-large-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/max-prefixes
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_community_send_large_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_max_prefixes_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -29317,21 +38351,17 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_send
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/force-check
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_soft_reconfiguration_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_force_check_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -29340,36 +38370,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_soft
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/warning-only
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weight_attribute_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_weight_modify(args);
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weight_attribute_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_weight_destroy(args);
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -29378,9 +38404,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_weig
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/add-paths/path-type
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/restart-timer
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_add_paths_path_type_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -29395,11 +38421,26 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_add_
        return NB_OK;
 }
 
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -29414,7 +38455,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_p
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -29431,9 +38472,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_p
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_origin_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -29448,7 +38489,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_p
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_origin_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -29465,44 +38506,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_p
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tr-restart-timer
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_replace_peer_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_OVERRIDE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/attr-unchanged/as-path-unchanged
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchanged_as_path_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -29511,44 +38540,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/attr-unchanged/next-hop-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchanged_next_hop_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/attr-unchanged/med-unchanged
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchanged_med_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -29557,10 +38574,10 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tw-warning-only
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_create(
-       struct nb_cb_create_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -29574,17 +38591,16 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_pref
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_prefix_limit_list_destroy(
-                       args);
+               /* TODO: implement me. */
+               break;
        }
 
        return NB_OK;
@@ -29592,17 +38608,21 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/nexthop-self/next-hop-self
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_nexthop_self_next_hop_self_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -29611,17 +38631,21 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/force-check
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/nexthop-self/next-hop-self-force
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_force_check_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_nexthop_self_next_hop_self_force_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -29630,32 +38654,44 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as-all
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_all_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_warning_only_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as-all-replace
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_all_replace_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -29664,32 +38700,44 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as-replace
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_replace_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -29698,32 +38746,44 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/route-reflector/route-reflector-client
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/route-server/route-server-client
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_route_server_route_server_client_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -29732,32 +38792,44 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/send-community/send-community
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_send_community_send_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/send-community/send-ext-community
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_send_community_send_ext_community_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -29766,32 +38838,44 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/send-community/send-large-community
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_send_community_send_large_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/soft-reconfiguration
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_soft_reconfiguration_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -29800,32 +38884,36 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/weight/weight-attribute
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_weight_modify(args);
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_weight_destroy(args);
+
                break;
        }
 
@@ -29834,33 +38922,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/rmap-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -29868,45 +38956,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_pref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/rmap-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_nexthop_self_next_hop_self_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/nexthop-self/next-hop-self-force
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_nexthop_self_next_hop_self_force_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_OUT);
        }
 
        return NB_OK;
@@ -29914,45 +38990,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_next
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/plist-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_all_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_IN);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as-all-replace
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_all_replace_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_IN);
        }
 
        return NB_OK;
@@ -29960,45 +39024,33 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_priv
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/plist-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as-replace
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_replace_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+       case NB_EV_ABORT:
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -30006,44 +39058,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_priv
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/access-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_route_reflector_route_reflector_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/route-server/route-server-client
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_route_server_route_server_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -30052,44 +39092,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_rout
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/send-community/send-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/access-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_community_send_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/send-community/send-ext-community
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_community_send_ext_community_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -30098,44 +39126,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_send
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/send-community/send-large-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/as-path-filter-list-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_community_send_large_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/soft-reconfiguration
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_soft_reconfiguration_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -30144,36 +39160,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_soft
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/as-path-filter-list-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weight_attribute_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_weight_modify(args);
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weight_attribute_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_as_path_filter_list_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_weight_destroy(args);
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -30182,9 +39194,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l3vpn_ipv6_unicast_weig
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/unsuppress-map-import
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -30199,7 +39211,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_opti
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -30216,9 +39228,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_opti
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/filter-config/unsuppress-map-export
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -30233,7 +39245,7 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_opti
        return NB_OK;
 }
 
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_filter_config_unsuppress_map_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -30250,21 +39262,17 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_opti
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/add-paths/path-type
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_options_replace_peer_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_OVERRIDE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -30273,44 +39281,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_as_path_opti
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/as-path-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/as-path-options/allow-own-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_as_path_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/next-hop-unchanged
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_next_hop_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_as_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -30319,44 +39315,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchang
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/med-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/as-path-options/allow-own-origin-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_med_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_origin_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/nexthop-self/next-hop-self
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_nexthop_self_next_hop_self_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_origin_as_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -30365,9 +39349,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_nexthop_self
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/nexthop-self/next-hop-self-force
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/as-path-options/replace-peer-as
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_nexthop_self_next_hop_self_force_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options_replace_peer_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -30376,8 +39360,8 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_nexthop_self
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_OVERRIDE,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -30388,21 +39372,17 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_nexthop_self
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/default-originate/originate
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_route_reflector_route_reflector_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_default_originate_originate_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -30411,44 +39391,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_route_reflec
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/route-server/route-server-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/default-originate/route-map
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_route_server_route_server_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_default_originate_route_map_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/soft-reconfiguration
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_soft_reconfiguration_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_default_originate_route_map_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -30457,9 +39425,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_soft_reconfi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/attr-unchanged/as-path-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_reflector_route_reflector_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_as_path_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -30468,8 +39436,8 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_ref
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -30480,9 +39448,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_ref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/route-server/route-server-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/attr-unchanged/next-hop-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_server_route_server_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_next_hop_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -30491,8 +39459,8 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_ser
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -30503,9 +39471,9 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_ser
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/attr-unchanged/med-unchanged
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_soft_reconfiguration_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_med_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -30514,8 +39482,8 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_soft_reco
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_MED_UNCHANGED,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -30526,44 +39494,32 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_soft_reco
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/orf-capability/orf-send
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_route_reflector_route_reflector_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_send_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/route-server/route-server-client
- */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_route_server_route_server_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_send_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -30572,61 +39528,25 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_route_ser
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/orf-capability/orf-receive
  */
-int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv6_flowspec_soft_reconfiguration_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_receive_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_unnumbered_neighbor_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-static int bgp_peer_group_afi_safi_flag_modify(struct nb_cb_modify_args *args,
-                                              uint32_t flags, bool set)
-{
-       struct bgp *bgp;
-       const char *peer_str;
-       struct peer *peer;
-       const struct lyd_node *nbr_dnode;
-       const struct lyd_node *nbr_af_dnode;
-       const char *af_name;
-       afi_t afi;
-       safi_t safi;
-
-       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
-       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
-       yang_afi_safi_identity2value(af_name, &afi, &safi);
-       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "peer-group");
-       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
-       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
-       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
-
-       if (peer_af_flag_modify_nb(peer, afi, safi, flags, set, args->errmsg,
-                                  args->errmsg_len)
-           < 0)
-               return NB_ERR_INCONSISTENCY;
-
-       return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/add-paths/path-type
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_add_paths_path_type_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_receive_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -30642,9 +39562,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_add_paths_path_ty
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/orf-capability/orf-both
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_both_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -30659,7 +39579,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_a
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_both_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -30676,10 +39596,10 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_a
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_origin_as_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_create(
+       struct nb_cb_create_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -30693,16 +39613,16 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_a
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_allow_own_origin_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
-               break;
+               return bgp_peer_group_afi_safi_prefix_limit_list_destroy(args);
        }
 
        return NB_OK;
@@ -30710,21 +39630,17 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_a
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/max-prefixes
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_replace_peer_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_max_prefixes_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_OVERRIDE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -30733,39 +39649,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_as_path_options_r
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast/default-originate
- */
-void bgp_peer_group_afi_safi_default_originate_apply_finish(
-       struct nb_cb_apply_finish_args *args)
-{
-       struct bgp *bgp;
-       const char *peer_str;
-       struct peer *peer;
-       const struct lyd_node *nbr_dnode;
-       const struct lyd_node *nbr_af_dnode;
-       const char *af_name;
-       afi_t afi;
-       safi_t safi;
-
-       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
-       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
-       yang_afi_safi_identity2value(af_name, &afi, &safi);
-
-       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "peer-group");
-       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
-       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
-       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
-       if (!peer)
-               return;
-
-       bgp_peer_afi_safi_default_originate_apply(args, peer, afi, safi);
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/default-originate/originate
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/force-check
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_default_originate_originate_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_force_check_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -30782,9 +39668,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_default_originate
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/default-originate/route-map
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/warning-only
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_default_originate_route_map_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -30799,7 +39685,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_default_originate
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_default_originate_route_map_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -30814,50 +39700,12 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_default_originate
        return NB_OK;
 }
 
-static int bgp_peer_group_afi_safi_prefix_limit_list_destroy(
-       struct nb_cb_destroy_args *args)
-{
-       struct bgp *bgp;
-       const char *peer_str;
-       struct peer *peer;
-       const struct lyd_node *nbr_dnode;
-       const struct lyd_node *nbr_af_dnode;
-       const char *af_name;
-       afi_t afi;
-       safi_t safi;
-       int direction;
-
-       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
-       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
-       yang_afi_safi_identity2value(af_name, &afi, &safi);
-
-       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "peer-group");
-       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
-       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
-       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
-       if (!peer)
-               return NB_ERR_INCONSISTENCY;
-
-       direction = yang_dnode_get_enum(args->dnode, "./direction");
-
-       switch (direction) {
-       case 1:
-               peer_maximum_prefix_unset(peer, afi, safi);
-               break;
-       case 2:
-               UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT);
-               peer->pmax_out[afi][safi] = 0;
-               break;
-       }
-
-       return NB_OK;
-}
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/restart-timer
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_create(
-       struct nb_cb_create_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_restart_timer_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -30871,51 +39719,26 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_dire
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_restart_timer_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_prefix_limit_list_destroy(args);
+               /* TODO: implement me. */
+               break;
        }
 
        return NB_OK;
 }
 
-void bgp_peer_group_afi_safi_prefix_limit_apply_finish(
-       struct nb_cb_apply_finish_args *args)
-{
-       struct bgp *bgp;
-       const char *peer_str;
-       struct peer *peer;
-       const struct lyd_node *nbr_dnode;
-       const struct lyd_node *nbr_af_dnode;
-       const char *af_name;
-       afi_t afi;
-       safi_t safi;
-
-       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
-       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
-       yang_afi_safi_identity2value(af_name, &afi, &safi);
-
-       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "peer-group");
-       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
-       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
-       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
-       if (!peer)
-               return;
-
-       bgp_peer_afi_safi_maximum_prefix_set(args, peer, afi, safi);
-}
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -30930,12 +39753,8 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_dire
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/force-check
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_force_check_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -30951,9 +39770,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -30968,7 +39787,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_dire
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -30985,9 +39804,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tr-restart-timer
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31002,7 +39821,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_dire
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -31019,9 +39838,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31036,7 +39855,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_dire
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -31053,9 +39872,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tw-warning-only
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31070,7 +39889,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_dire
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -31087,32 +39906,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/nexthop-self/next-hop-self
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_nexthop_self_next_hop_self_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/nexthop-self/next-hop-self-force
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_nexthop_self_next_hop_self_force_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -31121,32 +39952,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as-all
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_all_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as-all-replace
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_all_replace_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -31155,32 +39998,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as-replace
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_replace_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -31189,9 +40044,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/route-reflector/route-reflector-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_nexthop_self_next_hop_self_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31201,7 +40056,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_nexthop_self_next
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -31212,9 +40067,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_nexthop_self_next
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/nexthop-self/next-hop-self-force
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/route-server/route-server-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_nexthop_self_next_hop_self_force_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31224,7 +40079,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_nexthop_self_next
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       args, PEER_FLAG_RSERVER_CLIENT,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -31235,9 +40090,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_nexthop_self_next
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/send-community/send-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_all_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_send_community_send_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31247,7 +40102,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+                       args, PEER_FLAG_SEND_COMMUNITY,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -31258,9 +40113,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as-all-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/send-community/send-ext-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_all_replace_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_send_community_send_ext_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31270,7 +40125,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -31281,9 +40136,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/send-community/send-large-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_send_community_send_large_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31293,7 +40148,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
+                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -31304,9 +40159,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/private-as/remove-private-as-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/soft-reconfiguration
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove_private_as_replace_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31316,7 +40171,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
+                       args, PEER_FLAG_SOFT_RECONFIG,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -31325,70 +40180,11 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_private_as_remove
        return NB_OK;
 }
 
-static int bgp_peer_group_afi_safi_weight_modify(struct nb_cb_modify_args *args)
-{
-       struct bgp *bgp;
-       const char *peer_str;
-       struct peer *peer;
-       const struct lyd_node *nbr_dnode;
-       const struct lyd_node *nbr_af_dnode;
-       const char *af_name;
-       uint16_t weight;
-       afi_t afi;
-       safi_t safi;
-       int ret;
-
-       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
-       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
-       yang_afi_safi_identity2value(af_name, &afi, &safi);
-
-       nbr_dnode = yang_dnode_get_parent(args->dnode, "peer-group");
-       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
-       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
-       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
-
-       weight = yang_dnode_get_uint16(args->dnode, NULL);
-
-       ret = peer_weight_set(peer, afi, safi, weight);
-       if (bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret) < 0)
-               return NB_ERR_INCONSISTENCY;
-
-       return NB_OK;
-}
-
-static int
-bgp_peer_group_afi_safi_weight_destroy(struct nb_cb_destroy_args *args)
-{
-       struct bgp *bgp;
-       const char *peer_str;
-       struct peer *peer;
-       const struct lyd_node *nbr_dnode;
-       const struct lyd_node *nbr_af_dnode;
-       const char *af_name;
-       afi_t afi;
-       safi_t safi;
-       int ret;
-
-       nbr_af_dnode = yang_dnode_get_parent(args->dnode, "afi-safi");
-       af_name = yang_dnode_get_string(nbr_af_dnode, "./afi-safi-name");
-       yang_afi_safi_identity2value(af_name, &afi, &safi);
-       nbr_dnode = yang_dnode_get_parent(nbr_af_dnode, "peer-group");
-       bgp = nb_running_get_entry(nbr_dnode, NULL, true);
-       peer_str = yang_dnode_get_string(nbr_dnode, "./peer-group-name");
-       peer = bgp_peer_group_peer_lookup(bgp, peer_str);
-
-       ret = peer_weight_unset(peer, afi, safi);
-       if (bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret) < 0)
-               return NB_ERR_INCONSISTENCY;
-
-       return NB_OK;
-}
-
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/weight/weight-attribute
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_weight_weight_attribute_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_weight_weight_attribute_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31405,7 +40201,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_weight_weight_att
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_weight_weight_attribute_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -31424,45 +40220,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_weight_weight_att
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/rmap-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_route_reflector_route_reflector_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_IN);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/route-server/route-server-client
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_route_server_route_server_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -31470,45 +40254,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_route_server_rout
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/send-community/send-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/rmap-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_send_community_send_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/send-community/send-ext-community
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_send_community_send_ext_community_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_OUT);
        }
 
        return NB_OK;
@@ -31516,45 +40288,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_send_community_se
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/send-community/send-large-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/plist-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_send_community_send_large_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_IN);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/soft-reconfiguration
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_soft_reconfiguration_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_IN);
        }
 
        return NB_OK;
@@ -31562,22 +40322,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_soft_reconfigurat
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/attr-unchanged/as-path-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/plist-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_attr_unchanged_as_path_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
+               break;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
 
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_plist_export_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 bgp_peer_group_afi_safi_plist_destroy(args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -31585,44 +40356,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_attr_unchanged_as
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/attr-unchanged/next-hop-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/access-list-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_attr_unchanged_next_hop_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/attr-unchanged/med-unchanged
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_attr_unchanged_med_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -31631,9 +40390,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_attr_unchanged_me
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/orf-capability/orf-send
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/access-list-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_send_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31648,7 +40407,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_or
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_send_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_access_list_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -31665,9 +40424,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_or
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/orf-capability/orf-receive
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/as-path-filter-list-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_receive_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31682,7 +40441,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_or
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_receive_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -31699,9 +40458,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_or
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/orf-capability/orf-both
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/as-path-filter-list-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_both_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31716,7 +40475,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_or
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_orf_both_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_as_path_filter_list_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -31733,9 +40492,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_orf_capability_or
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/rmap-import
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/unsuppress-map-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_import_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31750,7 +40509,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_rma
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_import_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -31767,9 +40526,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_rma
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/rmap-export
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/filter-config/unsuppress-map-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_export_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31784,7 +40543,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_rma
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_rmap_export_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_filter_config_unsuppress_map_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -31801,9 +40560,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_rma
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/plist-import
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/add-paths/path-type
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_import_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31818,7 +40577,26 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_pli
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_import_destroy(
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/as-path-options/allow-own-as
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_as_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -31835,9 +40613,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_pli
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/plist-export
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/as-path-options/allow-own-origin-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_export_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_origin_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31852,7 +40630,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_pli
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_plist_export_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_origin_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -31869,25 +40647,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_pli
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/access-list-import
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/as-path-options/replace-peer-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_import_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_as_path_options_replace_peer_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_OVERRIDE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_import_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/default-originate/originate
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_default_originate_originate_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -31903,9 +40689,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_acc
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/access-list-export
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/default-originate/route-map
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_export_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_default_originate_route_map_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31920,7 +40706,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_acc
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_access_list_export_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_default_originate_route_map_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -31937,32 +40723,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_acc
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/as-path-filter-list-import
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/attr-unchanged/as-path-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_import_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_attr_unchanged_as_path_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_import_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/attr-unchanged/next-hop-unchanged
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_attr_unchanged_next_hop_unchanged_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -31971,9 +40769,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_as_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/as-path-filter-list-export
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/attr-unchanged/med-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_export_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_attr_unchanged_med_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_MED_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/orf-capability/orf-send
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_send_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -31988,7 +40809,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_as_
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_as_path_filter_list_export_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_send_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -32005,9 +40826,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_as_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/unsuppress-map-import
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/orf-capability/orf-receive
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_import_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_receive_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -32022,7 +40843,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_uns
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_import_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_receive_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -32039,9 +40860,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_uns
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast/filter-config/unsuppress-map-export
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/orf-capability/orf-both
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_export_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_both_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -32056,7 +40877,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_uns
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_unsuppress_map_export_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_both_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -32073,10 +40894,10 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_unicast_filter_config_uns
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/nexthop-local-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_nexthop_local_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_create(
+       struct nb_cb_create_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -32090,20 +40911,16 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_nexthop_local_unc
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/add-paths/path-type
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_add_paths_path_type_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
-               break;
+               return bgp_peer_group_afi_safi_prefix_limit_list_destroy(args);
        }
 
        return NB_OK;
@@ -32111,9 +40928,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_add_paths_path_ty
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/max-prefixes
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_max_prefixes_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -32128,8 +40945,12 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_as_path_options_a
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_as_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/force-check
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_force_check_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -32145,9 +40966,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_as_path_options_a
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/warning-only
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_origin_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -32162,7 +40983,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_as_path_options_a
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_as_path_options_allow_own_origin_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -32179,33 +41000,25 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_as_path_options_a
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/restart-timer
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_as_path_options_replace_peer_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_OVERRIDE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/default-originate/originate
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_default_originate_originate_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -32221,9 +41034,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_default_originate
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/default-originate/route-map
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_default_originate_route_map_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -32238,7 +41051,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_default_originate
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_default_originate_route_map_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -32255,44 +41068,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_default_originate
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/attr-unchanged/as-path-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_attr_unchanged_as_path_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/attr-unchanged/next-hop-unchanged
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_attr_unchanged_next_hop_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -32301,21 +41102,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_attr_unchanged_ne
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/attr-unchanged/med-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tr-restart-timer
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_attr_unchanged_med_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
 
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -32324,9 +41136,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_attr_unchanged_me
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/orf-capability/orf-send
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_send_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -32341,7 +41153,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_or
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_send_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -32358,9 +41170,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_or
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/orf-capability/orf-receive
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tw-warning-only
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_receive_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -32375,7 +41187,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_or
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_receive_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -32392,32 +41204,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_or
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/orf-capability/orf-both
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/nexthop-self/next-hop-self
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_both_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_nexthop_self_next_hop_self_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_orf_both_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/nexthop-self/next-hop-self-force
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_nexthop_self_next_hop_self_force_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -32426,25 +41250,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_orf_capability_or
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as-all
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_create(
-       struct nb_cb_create_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_all_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as-all-replace
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_all_replace_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -32452,7 +41284,11 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_dire
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_prefix_limit_list_destroy(args);
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
        }
 
        return NB_OK;
@@ -32460,17 +41296,21 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -32479,17 +41319,21 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/force-check
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as-replace
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_force_check_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -32498,32 +41342,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/route-reflector/route-reflector-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_warning_only_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/route-server/route-server-client
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_route_server_route_server_client_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -32532,32 +41388,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/send-community/send-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_send_community_send_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/send-community/send-ext-community
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_send_community_send_ext_community_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -32566,32 +41434,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/send-community/send-large-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_send_community_send_large_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/soft-reconfiguration
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_soft_reconfiguration_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -32600,32 +41480,36 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/weight/weight-attribute
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_weight_weight_attribute_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_weight_modify(args);
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_weight_destroy(args);
+
                break;
        }
 
@@ -32634,33 +41518,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/rmap-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -32668,33 +41552,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/rmap-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_rmap_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_OUT);
        }
 
        return NB_OK;
@@ -32702,33 +41586,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/plist-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_IN);
        }
 
        return NB_OK;
@@ -32736,45 +41620,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_prefix_limit_dire
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/plist-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_nexthop_self_next_hop_self_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/nexthop-self/next-hop-self-force
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_nexthop_self_next_hop_self_force_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -32782,44 +41654,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_nexthop_self_next
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/access-list-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_all_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as-all-replace
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_all_replace_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -32828,44 +41688,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_private_as_remove
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/access-list-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/private-as/remove-private-as-replace
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_private_as_remove_private_as_replace_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -32874,44 +41722,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_private_as_remove
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/as-path-filter-list-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_route_reflector_route_reflector_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/route-server/route-server-client
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_route_server_route_server_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -32920,44 +41756,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_route_server_rout
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/send-community/send-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/as-path-filter-list-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_send_community_send_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/send-community/send-ext-community
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_send_community_send_ext_community_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -32966,44 +41790,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_send_community_se
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/send-community/send-large-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/unsuppress-map-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_send_community_send_large_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/soft-reconfiguration
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_soft_reconfiguration_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -33012,36 +41824,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_soft_reconfigurat
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/filter-config/unsuppress-map-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_weight_modify(args);
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_weight_weight_attribute_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_filter_config_unsuppress_map_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_weight_destroy(args);
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -33050,9 +41858,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_unicast_weight_weight_att
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/add-paths/path-type
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/add-paths/path-type
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_add_paths_path_type_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33069,9 +41877,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_add_paths_path_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/allow-own-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33086,7 +41894,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -33103,9 +41911,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/allow-own-origin-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_origin_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_origin_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33120,7 +41928,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options_allow_own_origin_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_origin_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -33137,9 +41945,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/replace-peer-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options_replace_peer_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_replace_peer_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33160,9 +41968,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_as_path_options
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/default-originate/originate
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/default-originate/originate
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_default_originate_originate_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_default_originate_originate_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33179,9 +41987,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_default_origina
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/default-originate/route-map
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/default-originate/route-map
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_default_originate_route_map_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_default_originate_route_map_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33196,7 +42004,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_default_origina
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_default_originate_route_map_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_default_originate_route_map_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -33213,9 +42021,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_default_origina
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/attr-unchanged/as-path-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/attr-unchanged/as-path-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_as_path_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unchanged_as_path_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33236,9 +42044,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/attr-unchanged/next-hop-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/attr-unchanged/next-hop-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_next_hop_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unchanged_next_hop_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33259,9 +42067,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/attr-unchanged/med-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/attr-unchanged/med-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_med_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unchanged_med_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33282,9 +42090,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_attr_unchanged_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/orf-capability/orf-send
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/orf-capability/orf-send
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_send_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_send_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33299,7 +42107,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_send_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_send_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -33316,9 +42124,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/orf-capability/orf-receive
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/orf-capability/orf-receive
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_receive_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_receive_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33333,7 +42141,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_receive_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_receive_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -33350,9 +42158,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/orf-capability/orf-both
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/orf-capability/orf-both
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_both_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_both_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33367,7 +42175,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_orf_both_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_both_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -33384,9 +42192,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_orf_capability_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_create(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_create(
        struct nb_cb_create_args *args)
 {
        switch (args->event) {
@@ -33401,7 +42209,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -33418,9 +42226,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/max-prefixes
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_max_prefixes_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33437,9 +42245,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/force-check
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/force-check
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_force_check_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_force_check_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33456,9 +42264,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/warning-only
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33473,7 +42281,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_warning_only_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -33490,9 +42298,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/restart-timer
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33507,7 +42315,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_restart_timer_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -33524,9 +42332,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33541,7 +42349,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -33558,9 +42366,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33575,7 +42383,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -33592,9 +42400,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tr-restart-timer
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33609,7 +42417,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -33626,9 +42434,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33643,7 +42451,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -33660,9 +42468,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tw-warning-only
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33677,7 +42485,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -33694,9 +42502,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/nexthop-self/next-hop-self
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_nexthop_self_next_hop_self_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_nexthop_self_next_hop_self_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33717,9 +42525,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_nexthop_self_ne
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/nexthop-self/next-hop-self-force
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/nexthop-self/next-hop-self-force
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_nexthop_self_next_hop_self_force_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_nexthop_self_next_hop_self_force_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33740,9 +42548,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_nexthop_self_ne
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as-all
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_all_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_all_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33763,9 +42571,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_private_as_remo
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as-all-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as-all-replace
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_all_replace_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_all_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33786,9 +42594,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_private_as_remo
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33809,9 +42617,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_private_as_remo
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/private-as/remove-private-as-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as-replace
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_private_as_remove_private_as_replace_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33832,9 +42640,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_private_as_remo
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/route-reflector/route-reflector-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_route_reflector_route_reflector_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33855,9 +42663,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_route_reflector
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/route-server/route-server-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/route-server/route-server-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_route_server_route_server_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33878,9 +42686,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_route_server_ro
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/send-community/send-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/send-community/send-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_send_community_send_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_send_community_send_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33901,9 +42709,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_send_community_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/send-community/send-ext-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/send-community/send-ext-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_send_community_send_ext_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_send_community_send_ext_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33924,9 +42732,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_send_community_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/send-community/send-large-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/send-community/send-large-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_send_community_send_large_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_send_community_send_large_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33947,9 +42755,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_send_community_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/soft-reconfiguration
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_soft_reconfiguration_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33970,9 +42778,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_soft_reconfigur
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/weight/weight-attribute
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_weight_weight_attribute_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight_attribute_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -33989,7 +42797,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_weight_weight_a
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_weight_weight_attribute_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -34008,52 +42816,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_multicast_weight_weight_a
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/add-paths/path-type
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/rmap-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_add_paths_path_type_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
-       }
-
-       return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/as-path-options/allow-own-as
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_as_modify(
-       struct nb_cb_modify_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
        case NB_EV_APPLY:
-               /* TODO: implement me. */
-               break;
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -34061,33 +42850,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_as_path_options
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/rmap-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_origin_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_as_path_options_allow_own_origin_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_rmap_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_OUT);
        }
 
        return NB_OK;
@@ -34095,41 +42884,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_as_path_options
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/plist-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_as_path_options_replace_peer_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_OVERRIDE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_IN);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/default-originate/originate
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_default_originate_originate_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
+       case NB_EV_ABORT:
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_IN);
        }
 
        return NB_OK;
@@ -34137,33 +42918,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_default_origina
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/default-originate/route-map
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/plist-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_default_originate_route_map_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_default_originate_route_map_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_plist_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -34171,44 +42952,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_default_origina
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/attr-unchanged/as-path-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/access-list-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_attr_unchanged_as_path_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/attr-unchanged/next-hop-unchanged
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_attr_unchanged_next_hop_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -34217,21 +42986,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_attr_unchanged_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/attr-unchanged/med-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/access-list-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_attr_unchanged_med_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
 
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -34240,9 +43020,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_attr_unchanged_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/orf-capability/orf-send
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/as-path-filter-list-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_send_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -34257,7 +43037,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_send_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -34274,9 +43054,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/orf-capability/orf-receive
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/as-path-filter-list-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_receive_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -34291,7 +43071,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_receive_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_as_path_filter_list_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -34308,9 +43088,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/orf-capability/orf-both
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/unsuppress-map-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_both_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -34325,7 +43105,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_orf_both_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -34342,10 +43122,10 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_orf_capability_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/filter-config/unsuppress-map-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_create(
-       struct nb_cb_create_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -34359,16 +43139,16 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_filter_config_unsuppress_map_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_prefix_limit_list_destroy(args);
+               /* TODO: implement me. */
+               break;
        }
 
        return NB_OK;
@@ -34376,9 +43156,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/add-paths/path-type
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -34395,9 +43175,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/force-check
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/as-path-options/allow-own-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_force_check_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -34412,11 +43192,26 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
        return NB_OK;
 }
 
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_as_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/as-path-options/allow-own-origin-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_origin_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -34431,7 +43226,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_warning_only_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_origin_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -34448,25 +43243,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/as-path-options/replace-peer-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_replace_peer_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_OVERRIDE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_restart_timer_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/default-originate/originate
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_default_originate_originate_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -34482,9 +43285,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/default-originate/route-map
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_default_originate_route_map_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -34499,7 +43302,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_default_originate_route_map_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -34516,32 +43319,67 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/attr-unchanged/as-path-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_attr_unchanged_as_path_unchanged_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/attr-unchanged/next-hop-unchanged
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_attr_unchanged_next_hop_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/attr-unchanged/med-unchanged
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_attr_unchanged_med_unchanged_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_MED_UNCHANGED,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -34550,9 +43388,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/orf-capability/orf-send
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_send_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -34567,7 +43405,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_send_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -34584,9 +43422,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/orf-capability/orf-receive
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_receive_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -34601,7 +43439,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_receive_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -34618,9 +43456,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/orf-capability/orf-both
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_both_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -34635,7 +43473,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_both_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -34652,33 +43490,25 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_prefix_limit_di
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_nexthop_self_next_hop_self_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_create(
+       struct nb_cb_create_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/nexthop-self/next-hop-self-force
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_nexthop_self_next_hop_self_force_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -34686,11 +43516,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_nexthop_self_ne
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
+               return bgp_peer_group_afi_safi_prefix_limit_list_destroy(args);
        }
 
        return NB_OK;
@@ -34698,21 +43524,17 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_nexthop_self_ne
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/max-prefixes
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_all_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_max_prefixes_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -34721,21 +43543,17 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_private_as_remo
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as-all-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/force-check
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_all_replace_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_force_check_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -34744,44 +43562,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_private_as_remo
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/warning-only
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/private-as/remove-private-as-replace
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_private_as_remove_private_as_replace_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -34790,44 +43596,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_private_as_remo
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/restart-timer
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_route_reflector_route_reflector_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/route-server/route-server-client
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_route_server_route_server_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -34836,44 +43630,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_route_server_ro
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/send-community/send-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_send_community_send_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/send-community/send-ext-community
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_send_community_send_ext_community_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -34882,44 +43664,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_send_community_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/send-community/send-large-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_send_community_send_large_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/soft-reconfiguration
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_soft_reconfiguration_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -34928,36 +43698,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_soft_reconfigur
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tr-restart-timer
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_weight_weight_attribute_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_weight_modify(args);
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_weight_weight_attribute_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_weight_destroy(args);
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -34966,9 +43732,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_multicast_weight_weight_a
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/add-paths/path-type
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_add_paths_path_type_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -34983,12 +43749,8 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_add_paths
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/allow-own-as
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -35002,8 +43764,12 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_o
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_as_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tw-warning-only
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -35017,12 +43783,8 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_o
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/allow-own-origin-as
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_origin_as_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -35036,15 +43798,23 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_o
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_allow_own_origin_as_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/nexthop-self/next-hop-self
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_nexthop_self_next_hop_self_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -35053,9 +43823,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_o
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/nexthop-self/next-hop-self-force
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_options_replace_peer_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_nexthop_self_next_hop_self_force_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35065,7 +43835,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_o
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_OVERRIDE,
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -35076,17 +43846,21 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_as_path_o
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/default-originate/originate
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as-all
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_default_originate_originate_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_all_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -35095,32 +43869,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_default_o
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/default-originate/route-map
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as-all-replace
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_default_originate_route_map_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_all_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_default_originate_route_map_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -35129,9 +43915,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_default_o
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/attr-unchanged/as-path-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as-replace
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unchanged_as_path_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35141,7 +43927,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unch
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -35152,9 +43938,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unch
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/attr-unchanged/next-hop-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/route-reflector/route-reflector-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unchanged_next_hop_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35164,7 +43950,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unch
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -35175,9 +43961,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unch
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/attr-unchanged/med-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/route-server/route-server-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unchanged_med_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35187,7 +43973,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unch
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
+                       args, PEER_FLAG_RSERVER_CLIENT,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -35198,32 +43984,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_attr_unch
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/orf-capability/orf-send
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/send-community/send-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_send_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_send_community_send_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_send_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/send-community/send-ext-community
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_send_community_send_ext_community_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -35232,32 +44030,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capab
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/orf-capability/orf-receive
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/send-community/send-large-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_receive_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_send_community_send_large_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_receive_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/soft-reconfiguration
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_soft_reconfiguration_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -35266,32 +44076,36 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capab
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/orf-capability/orf-both
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/weight/weight-attribute
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_both_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_weight_weight_attribute_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_weight_modify(args);
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capability_orf_both_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_weight_destroy(args);
+
                break;
        }
 
@@ -35300,33 +44114,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_orf_capab
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/rmap-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_create(
-       struct nb_cb_create_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
+               break;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_prefix_limit_list_destroy(args);
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -35334,37 +44148,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/rmap-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/force-check
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_force_check_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_rmap_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_OUT);
        }
 
        return NB_OK;
@@ -35372,33 +44182,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/plist-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_IN);
        }
 
        return NB_OK;
@@ -35406,33 +44216,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/plist-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_plist_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -35440,9 +44250,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/access-list-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35457,7 +44267,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_li
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -35474,9 +44284,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/access-list-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35491,7 +44301,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_li
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_access_list_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -35508,9 +44318,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/as-path-filter-list-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35525,7 +44335,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_li
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -35542,9 +44352,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/as-path-filter-list-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35559,7 +44369,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_li
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_as_path_filter_list_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -35576,9 +44386,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/unsuppress-map-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35593,7 +44403,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_li
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -35610,44 +44420,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/filter-config/unsuppress-map-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_nexthop_self_next_hop_self_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/nexthop-self/next-hop-self-force
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_nexthop_self_next_hop_self_force_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -35656,21 +44454,17 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_nexthop_s
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/add-paths/path-type
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_all_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -35679,44 +44473,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_private_a
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as-all-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/as-path-options/allow-own-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_all_replace_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_as_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -35725,44 +44507,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_private_a
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/private-as/remove-private-as-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/as-path-options/allow-own-origin-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_private_as_remove_private_as_replace_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_origin_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/route-reflector/route-reflector-client
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_route_reflector_route_reflector_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_origin_as_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -35771,9 +44541,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_route_ref
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/route-server/route-server-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/as-path-options/replace-peer-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_route_server_route_server_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_replace_peer_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35783,7 +44553,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_route_ser
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
+                       args, PEER_FLAG_AS_OVERRIDE,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -35794,9 +44564,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_route_ser
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/send-community/send-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/attr-unchanged/as-path-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_send_community_send_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchanged_as_path_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35806,7 +44576,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_send_comm
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_COMMUNITY,
+                       args, PEER_FLAG_AS_PATH_UNCHANGED,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -35817,9 +44587,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_send_comm
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/send-community/send-ext-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/attr-unchanged/next-hop-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_send_community_send_ext_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchanged_next_hop_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35829,7 +44599,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_send_comm
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
+                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -35840,9 +44610,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_send_comm
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/send-community/send-large-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/attr-unchanged/med-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_send_community_send_large_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchanged_med_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35852,7 +44622,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_send_comm
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
+                       args, PEER_FLAG_MED_UNCHANGED,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -35863,33 +44633,25 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_send_comm
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_soft_reconfiguration_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_create(
+       struct nb_cb_create_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast/weight/weight-attribute
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight_attribute_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -35897,25 +44659,25 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_weight_we
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_weight_modify(args);
-
-               break;
+               return bgp_peer_group_afi_safi_prefix_limit_list_destroy(args);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_weight_weight_attribute_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/max-prefixes
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_max_prefixes_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_weight_destroy(args);
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -35924,9 +44686,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_labeled_unicast_weight_we
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/add-paths/path-type
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/force-check
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_add_paths_path_type_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_force_check_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35943,9 +44705,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_add_paths
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/warning-only
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35960,7 +44722,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_o
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -35977,9 +44739,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_o
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/restart-timer
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_origin_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -35994,7 +44756,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_o
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_allow_own_origin_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -36011,33 +44773,25 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_o
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_as_path_options_replace_peer_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_OVERRIDE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/default-originate/originate
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_default_originate_originate_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -36053,9 +44807,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_default_o
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/default-originate/route-map
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_default_originate_route_map_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -36070,7 +44824,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_default_o
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_default_originate_route_map_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -36087,67 +44841,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_default_o
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/attr-unchanged/as-path-unchanged
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_attr_unchanged_as_path_unchanged_modify(
-       struct nb_cb_modify_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
-       }
-
-       return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/attr-unchanged/next-hop-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tr-restart-timer
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_attr_unchanged_next_hop_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/attr-unchanged/med-unchanged
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_attr_unchanged_med_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -36156,9 +44875,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_attr_unch
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/orf-capability/orf-send
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_send_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -36173,7 +44892,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capab
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_send_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -36190,9 +44909,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capab
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/orf-capability/orf-receive
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tw-warning-only
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_receive_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -36207,7 +44926,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capab
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_receive_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -36224,32 +44943,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capab
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/orf-capability/orf-both
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/nexthop-self/next-hop-self
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_both_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_nexthop_self_next_hop_self_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capability_orf_both_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/nexthop-self/next-hop-self-force
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_nexthop_self_next_hop_self_force_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -36258,25 +44989,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_orf_capab
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as-all
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_create(
-       struct nb_cb_create_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_all_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as-all-replace
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_all_replace_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -36284,7 +45023,11 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_li
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_prefix_limit_list_destroy(args);
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
        }
 
        return NB_OK;
@@ -36292,17 +45035,21 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -36311,17 +45058,21 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/force-check
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as-replace
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_force_check_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -36330,32 +45081,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/route-reflector/route-reflector-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_warning_only_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/route-server/route-server-client
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_route_server_route_server_client_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -36364,32 +45127,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/send-community/send-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_community_send_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/send-community/send-ext-community
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_community_send_ext_community_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -36398,32 +45173,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/send-community/send-large-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_community_send_large_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/soft-reconfiguration
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_soft_reconfiguration_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -36432,32 +45219,36 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/weight/weight-attribute
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weight_attribute_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_weight_modify(args);
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weight_attribute_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_weight_destroy(args);
+
                break;
        }
 
@@ -36466,33 +45257,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/rmap-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -36500,33 +45291,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/rmap-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_rmap_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_OUT);
        }
 
        return NB_OK;
@@ -36534,33 +45325,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/plist-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_IN);
        }
 
        return NB_OK;
@@ -36568,45 +45359,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_prefix_li
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/plist-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_nexthop_self_next_hop_self_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/nexthop-self/next-hop-self-force
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_nexthop_self_next_hop_self_force_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -36614,44 +45393,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_nexthop_s
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/access-list-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_all_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as-all-replace
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_all_replace_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -36660,44 +45427,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_private_a
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/access-list-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/private-as/remove-private-as-replace
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_private_as_remove_private_as_replace_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -36706,44 +45461,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_private_a
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/as-path-filter-list-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_route_reflector_route_reflector_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/route-server/route-server-client
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_route_server_route_server_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -36752,44 +45495,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_route_ser
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/send-community/send-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/as-path-filter-list-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_send_community_send_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/send-community/send-ext-community
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_send_community_send_ext_community_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -36798,44 +45529,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_send_comm
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/send-community/send-large-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/unsuppress-map-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_send_community_send_large_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/soft-reconfiguration
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_soft_reconfiguration_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -36844,36 +45563,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_soft_reco
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/filter-config/unsuppress-map-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_weight_weight_attribute_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_weight_modify(args);
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_weight_weight_attribute_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_unsuppress_map_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_weight_destroy(args);
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -36882,9 +45597,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_labeled_unicast_weight_we
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/add-paths/path-type
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/add-paths/path-type
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_add_paths_path_type_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_add_paths_path_type_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -36901,9 +45616,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_add_paths_p
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/as-path-options/allow-own-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -36918,7 +45633,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_opt
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -36935,9 +45650,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_opt
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/as-path-options/allow-own-origin-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_origin_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_origin_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -36952,7 +45667,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_opt
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_allow_own_origin_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_origin_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -36969,9 +45684,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_opt
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/as-path-options/replace-peer-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_options_replace_peer_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_replace_peer_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -36992,9 +45707,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_as_path_opt
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/attr-unchanged/as-path-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/attr-unchanged/as-path-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchanged_as_path_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchanged_as_path_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37015,9 +45730,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchan
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/attr-unchanged/next-hop-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/attr-unchanged/next-hop-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchanged_next_hop_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchanged_next_hop_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37038,9 +45753,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchan
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/attr-unchanged/med-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/attr-unchanged/med-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchanged_med_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchanged_med_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37061,9 +45776,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_attr_unchan
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_create(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_create(
        struct nb_cb_create_args *args)
 {
        switch (args->event) {
@@ -37078,7 +45793,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -37095,9 +45810,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/max-prefixes
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_max_prefixes_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37114,9 +45829,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/force-check
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/force-check
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_force_check_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_force_check_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37133,9 +45848,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/warning-only
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37150,7 +45865,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_warning_only_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -37167,9 +45882,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/restart-timer
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37184,7 +45899,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -37201,9 +45916,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37218,7 +45933,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -37235,9 +45950,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37252,7 +45967,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -37269,9 +45984,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tr-restart-timer
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37286,7 +46001,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -37303,9 +46018,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37320,7 +46035,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -37337,9 +46052,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tw-warning-only
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37354,7 +46069,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -37371,9 +46086,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/nexthop-self/next-hop-self
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_nexthop_self_next_hop_self_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_nexthop_self_next_hop_self_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37394,9 +46109,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_nexthop_sel
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/nexthop-self/next-hop-self-force
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/nexthop-self/next-hop-self-force
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_nexthop_self_next_hop_self_force_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_nexthop_self_next_hop_self_force_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37417,9 +46132,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_nexthop_sel
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as-all
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_all_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_all_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37440,9 +46155,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as-all-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as-all-replace
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_all_replace_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_all_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37463,9 +46178,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37486,9 +46201,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/private-as/remove-private-as-replace
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as-replace
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_remove_private_as_replace_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_replace_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37509,9 +46224,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_private_as_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/route-reflector/route-reflector-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_route_reflector_route_reflector_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37532,9 +46247,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_route_refle
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/route-server/route-server-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/route-server/route-server-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_route_server_route_server_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37555,9 +46270,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_route_serve
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/send-community/send-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/send-community/send-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_community_send_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_community_send_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37578,9 +46293,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_commun
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/send-community/send-ext-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/send-community/send-ext-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_community_send_ext_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_community_send_ext_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37601,9 +46316,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_commun
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/send-community/send-large-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/send-community/send-large-community
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_community_send_large_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_community_send_large_community_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37624,9 +46339,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_send_commun
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/soft-reconfiguration
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_soft_reconfiguration_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37647,36 +46362,342 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_soft_reconf
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/weight/weight-attribute
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weight_attribute_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_weight_modify(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weight_attribute_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_weight_destroy(args);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/rmap-import
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_import_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 bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/rmap-export
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_rmap_export_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 bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/plist-import
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_import_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 bgp_peer_group_afi_safi_plist_destroy(args, FILTER_IN);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/plist-export
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_plist_export_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 bgp_peer_group_afi_safi_plist_destroy(args, FILTER_OUT);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/access-list-import
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/access-list-export
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/as-path-filter-list-import
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_import_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/as-path-filter-list-export
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_export_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/unsuppress-map-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weight_attribute_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_weight_modify(args);
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weight_attribute_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_weight_destroy(args);
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -37685,9 +46706,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv4_unicast_weight_weig
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/add-paths/path-type
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/filter-config/unsuppress-map-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_add_paths_path_type_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37702,11 +46723,26 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_add_paths_p
        return NB_OK;
 }
 
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37721,7 +46757,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_opt
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -37738,9 +46774,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_opt
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-origin-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_origin_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37755,7 +46791,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_opt
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_allow_own_origin_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -37772,9 +46808,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_opt
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/as-path-options/replace-peer-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/as-path-options/replace-peer-as
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_options_replace_peer_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_as_path_options_replace_peer_as_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37795,9 +46831,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_as_path_opt
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/attr-unchanged/as-path-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/as-path-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchanged_as_path_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_as_path_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37818,9 +46854,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchan
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/attr-unchanged/next-hop-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/next-hop-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchanged_next_hop_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_next_hop_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37841,9 +46877,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchan
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/attr-unchanged/med-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/med-unchanged
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchanged_med_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_med_unchanged_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -37864,25 +46900,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_attr_unchan
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/nexthop-self/next-hop-self
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_create(
-       struct nb_cb_create_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_nexthop_self_next_hop_self_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/nexthop-self/next-hop-self-force
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_nexthop_self_next_hop_self_force_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -37890,7 +46934,11 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limi
        case NB_EV_ABORT:
                return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_prefix_limit_list_destroy(args);
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
+               break;
        }
 
        return NB_OK;
@@ -37898,17 +46946,21 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/max-prefixes
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/route-reflector/route-reflector-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_max_prefixes_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -37917,17 +46969,21 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/force-check
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/route-server/route-server-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_force_check_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -37936,32 +46992,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/soft-reconfiguration
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_warning_only_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/route-reflector/route-reflector-client
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_route_reflector_route_reflector_client_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -37970,32 +47038,44 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/route-server/route-server-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_RSERVER_CLIENT,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_restart_timer_destroy(
-       struct nb_cb_destroy_args *args)
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/soft-reconfiguration
+ */
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_soft_reconfiguration_modify(
+       struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
+               return NB_OK;
        case NB_EV_APPLY:
-               /* TODO: implement me. */
+               return bgp_peer_group_afi_safi_flag_modify(
+                       args, PEER_FLAG_SOFT_RECONFIG,
+                       yang_dnode_get_bool(args->dnode, NULL));
+
                break;
        }
 
@@ -38004,33 +47084,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/rmap-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -38038,33 +47118,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tr-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/rmap-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_rmap_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_OUT);
        }
 
        return NB_OK;
@@ -38072,33 +47152,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tr-restart-timer
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/plist-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tr_restart_timer_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_IN);
        }
 
        return NB_OK;
@@ -38106,33 +47186,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tw-shutdown-threshold-pct
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/plist-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_shutdown_threshold_pct_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_plist_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -38140,9 +47220,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/prefix-limit/direction-list/options/tw-warning-only
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/access-list-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -38157,7 +47237,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limi
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limit_direction_list_options_tw_warning_only_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
@@ -38174,44 +47254,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_prefix_limi
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/nexthop-self/next-hop-self
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/access-list-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_nexthop_self_next_hop_self_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/nexthop-self/next-hop-self-force
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_nexthop_self_next_hop_self_force_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -38220,44 +47288,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_nexthop_sel
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as-all
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/as-path-filter-list-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_all_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as-all-replace
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_all_replace_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -38266,44 +47322,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/as-path-filter-list-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/private-as/remove-private-as-replace
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_remove_private_as_replace_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -38312,44 +47356,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_private_as_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/unsuppress-map-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_route_reflector_route_reflector_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/route-server/route-server-client
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_route_server_route_server_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -38358,21 +47390,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_route_serve
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/send-community/send-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/filter-config/unsuppress-map-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_community_send_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_COMMUNITY,
-                       yang_dnode_get_bool(args->dnode, NULL));
+               /* TODO: implement me. */
+               break;
+       }
 
+       return NB_OK;
+}
+
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
                break;
        }
 
@@ -38381,9 +47424,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_commun
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/send-community/send-ext-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/route-reflector/route-reflector-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_community_send_ext_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_route_reflector_route_reflector_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -38393,7 +47436,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_commun
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_EXT_COMMUNITY,
+                       args, PEER_FLAG_REFLECTOR_CLIENT,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -38404,9 +47447,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_commun
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/send-community/send-large-community
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/route-server/route-server-client
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_community_send_large_community_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_route_server_route_server_client_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -38416,7 +47459,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_commun
                return NB_OK;
        case NB_EV_APPLY:
                return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SEND_LARGE_COMMUNITY,
+                       args, PEER_FLAG_RSERVER_CLIENT,
                        yang_dnode_get_bool(args->dnode, NULL));
 
                break;
@@ -38427,9 +47470,9 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_send_commun
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/soft-reconfiguration
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_soft_reconfiguration_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_soft_reconfiguration_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
@@ -38450,37 +47493,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_soft_reconf
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast/weight/weight-attribute
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/rmap-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weight_attribute_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_weight_modify(args);
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weight_attribute_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_weight_destroy(args);
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_IN);
        }
 
        return NB_OK;
@@ -38488,33 +47527,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l3vpn_ipv6_unicast_weight_weig
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/rmap-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_OUT);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_rmap_export_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_IN);
        }
 
        return NB_OK;
@@ -38522,56 +47561,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_as_path_options_all
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/as-path-options/allow-own-origin-as
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/plist-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_IN);
        }
 
        return NB_OK;
 }
 
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_as_path_options_allow_own_origin_as_destroy(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_import_destroy(
        struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               /* TODO: implement me. */
                break;
-       }
-
-       return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/as-path-options/replace-peer-as
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_as_path_options_replace_peer_as_modify(
-       struct nb_cb_modify_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_OVERRIDE,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
-               break;
+               return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_OUT);
        }
 
        return NB_OK;
@@ -38579,45 +47595,33 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_as_path_options_rep
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/as-path-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/plist-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_as_path_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_AS_PATH_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_modify(args, FILTER_OUT);
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/next-hop-unchanged
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_next_hop_unchanged_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_plist_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
-       case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
                break;
+       case NB_EV_APPLY:
+               return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_OUT);
        }
 
        return NB_OK;
@@ -38625,44 +47629,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_next
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/attr-unchanged/med-unchanged
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/access-list-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_attr_unchanged_med_unchanged_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_MED_UNCHANGED,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/nexthop-self/next-hop-self
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_nexthop_self_next_hop_self_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -38671,44 +47663,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_nexthop_self_next_h
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/nexthop-self/next-hop-self-force
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/access-list-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_nexthop_self_next_hop_self_force_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_FORCE_NEXTHOP_SELF,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/route-reflector/route-reflector-client
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_route_reflector_route_reflector_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_access_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -38717,44 +47697,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_route_reflector_rou
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/route-server/route-server-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/as-path-filter-list-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_route_server_route_server_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/soft-reconfiguration
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_soft_reconfiguration_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -38763,44 +47731,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_soft_reconfiguratio
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/route-reflector/route-reflector-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/as-path-filter-list-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_route_reflector_route_reflector_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/route-server/route-server-client
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_route_server_route_server_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_as_path_filter_list_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -38809,44 +47765,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_route_server_rou
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/soft-reconfiguration
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/unsuppress-map-import
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_soft_reconfiguration_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/route-reflector/route-reflector-client
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_route_reflector_route_reflector_client_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_import_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_REFLECTOR_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
@@ -38855,44 +47799,32 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_route_reflector_
 
 /*
  * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/route-server/route-server-client
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/filter-config/unsuppress-map-export
  */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_route_server_route_server_client_modify(
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_modify(
        struct nb_cb_modify_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_RSERVER_CLIENT,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec/soft-reconfiguration
- */
-int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_soft_reconfiguration_modify(
-       struct nb_cb_modify_args *args)
+int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_unsuppress_map_export_destroy(
+       struct nb_cb_destroy_args *args)
 {
        switch (args->event) {
        case NB_EV_VALIDATE:
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-               return NB_OK;
        case NB_EV_APPLY:
-               return bgp_peer_group_afi_safi_flag_modify(
-                       args, PEER_FLAG_SOFT_RECONFIG,
-                       yang_dnode_get_bool(args->dnode, NULL));
-
+               /* TODO: implement me. */
                break;
        }
 
index cae11ae7bdd91f70e4e05e0486ef8adf470e1959..be2c474493f0c9d19413ffec5a2410b4de0207a9 100644 (file)
@@ -457,8 +457,16 @@ static int bgp_accept(struct thread *thread)
                        BGP_TIMER_OFF(
                                peer1->t_start); /* created in peer_create() */
 
-                       if (peer_active(peer1))
-                               BGP_EVENT_ADD(peer1, TCP_connection_open);
+                       if (peer_active(peer1)) {
+                               if (CHECK_FLAG(peer1->flags,
+                                              PEER_FLAG_TIMER_DELAYOPEN))
+                                       BGP_EVENT_ADD(
+                                               peer1,
+                                               TCP_connection_open_w_delay);
+                               else
+                                       BGP_EVENT_ADD(peer1,
+                                                     TCP_connection_open);
+                       }
 
                        return 0;
                }
@@ -595,7 +603,10 @@ static int bgp_accept(struct thread *thread)
        }
 
        if (peer_active(peer)) {
-               BGP_EVENT_ADD(peer, TCP_connection_open);
+               if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN))
+                       BGP_EVENT_ADD(peer, TCP_connection_open_w_delay);
+               else
+                       BGP_EVENT_ADD(peer, TCP_connection_open);
        }
 
        return 0;
@@ -639,7 +650,9 @@ static int bgp_update_address(struct interface *ifp, const union sockunion *dst,
        struct listnode *node;
        int common;
 
-       sockunion2hostprefix(dst, &d);
+       if (!sockunion2hostprefix(dst, &d))
+               return 1;
+
        sel = NULL;
        common = -1;
 
index 5d3667af1a79d7dd3cb8285b6dcb284f13a52577..29ab3d9c6c953d2e19a9f2cbad198cb093fe9b77 100644 (file)
@@ -31,6 +31,7 @@
 #include "nexthop.h"
 #include "vrf.h"
 #include "filter.h"
+#include "nexthop_group.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_table.h"
@@ -624,7 +625,7 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
        ret = zclient_send_rnh(zclient, command, &bnc->prefix, exact_match,
                               bnc->bgp->vrf_id);
        /* TBD: handle the failure */
-       if (ret < 0)
+       if (ret == ZCLIENT_SEND_FAILURE)
                flog_warn(EC_BGP_ZEBRA_SEND,
                          "sendmsg_nexthop: zclient_send_message() failed");
 
@@ -966,3 +967,83 @@ void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer)
                                                0);
        }
 }
+
+/****************************************************************************
+ * L3 NHGs are used for fast failover of nexthops in the dplane. These are
+ * the APIs for allocating L3 NHG ids. Management of the L3 NHG itself is
+ * left to the application using it.
+ * PS: Currently EVPN host routes is the only app using L3 NHG for fast
+ * failover of remote ES links.
+ ***************************************************************************/
+static bitfield_t bgp_nh_id_bitmap;
+static uint32_t bgp_l3nhg_start;
+
+/* XXX - currently we do nothing on the callbacks */
+static void bgp_l3nhg_add_cb(const char *name)
+{
+}
+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)
+{
+}
+
+static void bgp_l3nhg_zebra_init(void)
+{
+       static bool bgp_l3nhg_zebra_inited;
+       if (bgp_l3nhg_zebra_inited)
+               return;
+
+       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);
+}
+
+
+#define min(A, B) ((A) < (B) ? (A) : (B))
+void bgp_l3nhg_init(void)
+{
+       uint32_t id_max;
+
+       id_max = min(ZEBRA_NHG_PROTO_SPACING - 1, 16 * 1024);
+       bf_init(bgp_nh_id_bitmap, id_max);
+       bf_assign_zero_index(bgp_nh_id_bitmap);
+
+       if (BGP_DEBUG(nht, NHT) || BGP_DEBUG(evpn_mh, EVPN_MH_ES))
+               zlog_debug("bgp l3_nhg range %u - %u", bgp_l3nhg_start + 1,
+                          bgp_l3nhg_start + id_max);
+}
+
+void bgp_l3nhg_finish(void)
+{
+       bf_free(bgp_nh_id_bitmap);
+}
+
+uint32_t bgp_l3nhg_id_alloc(void)
+{
+       uint32_t nhg_id = 0;
+
+       bgp_l3nhg_zebra_init();
+       bf_assign_index(bgp_nh_id_bitmap, nhg_id);
+       if (nhg_id)
+               nhg_id += bgp_l3nhg_start;
+
+       return nhg_id;
+}
+
+void bgp_l3nhg_id_free(uint32_t nhg_id)
+{
+       if (!nhg_id || (nhg_id <= bgp_l3nhg_start))
+               return;
+
+       nhg_id -= bgp_l3nhg_start;
+
+       bf_release_index(bgp_nh_id_bitmap, nhg_id);
+}
index 4e015e4aaeb6aeee386b6aac3347258d191eb0eb..8451f0689d87aef79fa522c5980deac5e3f7da72 100644 (file)
@@ -90,4 +90,10 @@ extern void bgp_nht_register_nexthops(struct bgp *bgp);
 extern void bgp_nht_reg_enhe_cap_intfs(struct peer *peer);
 extern void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer);
 
+/* APIs for setting up and allocating L3 nexthop group ids */
+extern uint32_t bgp_l3nhg_id_alloc(void);
+extern void bgp_l3nhg_id_free(uint32_t nhg_id);
+extern void bgp_l3nhg_init(void);
+void bgp_l3nhg_finish(void);
+
 #endif /* _BGP_NHT_H */
index 6cfcb9cc3d2331d8cb4e2fee64d75075e4812e06..533518cf93654fce19d20b6d73459ebc438ba7c8 100644 (file)
@@ -760,6 +760,7 @@ static const struct message capcode_str[] = {
        {CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)"},
        {CAPABILITY_CODE_ORF_OLD, "ORF (Old)"},
        {CAPABILITY_CODE_FQDN, "FQDN"},
+       {CAPABILITY_CODE_ENHANCED_RR, "Enhanced Route Refresh"},
        {0}};
 
 /* Minimum sizes for length field of each cap (so not inc. the header) */
@@ -776,6 +777,7 @@ static const size_t cap_minsizes[] = {
                [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN,
                [CAPABILITY_CODE_ORF_OLD] = CAPABILITY_CODE_ORF_LEN,
                [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN,
+               [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN,
 };
 
 /* value the capability must be a multiple of.
@@ -796,6 +798,7 @@ static const size_t cap_modsizes[] = {
                [CAPABILITY_CODE_REFRESH_OLD] = 1,
                [CAPABILITY_CODE_ORF_OLD] = 1,
                [CAPABILITY_CODE_FQDN] = 1,
+               [CAPABILITY_CODE_ENHANCED_RR] = 1,
 };
 
 /**
@@ -863,6 +866,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
                case CAPABILITY_CODE_DYNAMIC_OLD:
                case CAPABILITY_CODE_ENHE:
                case CAPABILITY_CODE_FQDN:
+               case CAPABILITY_CODE_ENHANCED_RR:
                        /* Check length. */
                        if (caphdr.length < cap_minsizes[caphdr.code]) {
                                zlog_info(
@@ -913,10 +917,13 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
                                ret = 0; /* Don't return error for this */
                        }
                } break;
+               case CAPABILITY_CODE_ENHANCED_RR:
                case CAPABILITY_CODE_REFRESH:
                case CAPABILITY_CODE_REFRESH_OLD: {
                        /* BGP refresh capability */
-                       if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
+                       if (caphdr.code == CAPABILITY_CODE_ENHANCED_RR)
+                               SET_FLAG(peer->cap, PEER_CAP_ENHANCED_RR_RCV);
+                       else if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
                                SET_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV);
                        else
                                SET_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV);
@@ -1450,6 +1457,13 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
        stream_putc(s, CAPABILITY_CODE_REFRESH);
        stream_putc(s, CAPABILITY_CODE_REFRESH_LEN);
 
+       /* Enhanced Route Refresh. */
+       SET_FLAG(peer->cap, PEER_CAP_ENHANCED_RR_ADV);
+       stream_putc(s, BGP_OPEN_OPT_CAP);
+       stream_putc(s, CAPABILITY_CODE_ENHANCED_LEN + 2);
+       stream_putc(s, CAPABILITY_CODE_ENHANCED_RR);
+       stream_putc(s, CAPABILITY_CODE_ENHANCED_LEN);
+
        /* AS4 */
        SET_FLAG(peer->cap, PEER_CAP_AS4_ADV);
        stream_putc(s, BGP_OPEN_OPT_CAP);
index 5250a68581090d6dc870b20f821bbfa1bad9c6e8..471ac05c7cf0686abe90eae94d22c2a6996260a0 100644 (file)
@@ -49,6 +49,7 @@ struct graceful_restart_af {
 #define CAPABILITY_CODE_DYNAMIC_OLD    66 /* Dynamic Capability, deprecated since 2003 */
 #define CAPABILITY_CODE_DYNAMIC        67 /* Dynamic Capability */
 #define CAPABILITY_CODE_ADDPATH        69 /* Addpath Capability */
+#define CAPABILITY_CODE_ENHANCED_RR    70 /* Enhanced Route Refresh capability */
 #define CAPABILITY_CODE_FQDN           73 /* Advertise hostname capability */
 #define CAPABILITY_CODE_ENHE            5 /* Extended Next Hop Encoding */
 #define CAPABILITY_CODE_REFRESH_OLD   128 /* Route Refresh Capability(cisco) */
@@ -63,6 +64,7 @@ struct graceful_restart_af {
 #define CAPABILITY_CODE_ADDPATH_LEN     4
 #define CAPABILITY_CODE_ENHE_LEN        6 /* NRLI AFI = 2, SAFI = 2, Nexthop AFI = 2 */
 #define CAPABILITY_CODE_MIN_FQDN_LEN    2
+#define CAPABILITY_CODE_ENHANCED_LEN    0
 #define CAPABILITY_CODE_ORF_LEN         5
 
 /* Cooperative Route Filtering Capability.  */
index 3d73e34235978d8e1f7bc4e5d1a1b6b32358d07c..b7ecd8a49bfe05da6b858d85d629eed57801e37e 100644 (file)
@@ -444,6 +444,45 @@ int bgp_generate_updgrp_packets(struct thread *thread)
                         * yet.
                         */
                        if (!next_pkt || !next_pkt->buffer) {
+                               if (!paf->t_announce_route) {
+                                       /* Make sure we supress BGP UPDATES
+                                        * for normal processing later again.
+                                        */
+                                       UNSET_FLAG(paf->subgroup->sflags,
+                                                  SUBGRP_STATUS_FORCE_UPDATES);
+
+                                       /* If route-refresh BoRR message was
+                                        * already sent and we are done with
+                                        * re-announcing tables for a decent
+                                        * afi/safi, we ready to send
+                                        * EoRR request.
+                                        */
+                                       if (CHECK_FLAG(
+                                                   peer->af_sflags[afi][safi],
+                                                   PEER_STATUS_BORR_SEND)) {
+                                               bgp_route_refresh_send(
+                                                       peer, afi, safi, 0, 0,
+                                                       0,
+                                                       BGP_ROUTE_REFRESH_EORR);
+
+                                               SET_FLAG(peer->af_sflags[afi]
+                                                                       [safi],
+                                                        PEER_STATUS_EORR_SEND);
+                                               UNSET_FLAG(
+                                                       peer->af_sflags[afi]
+                                                                      [safi],
+                                                       PEER_STATUS_BORR_SEND);
+
+                                               if (bgp_debug_neighbor_events(
+                                                           peer))
+                                                       zlog_debug(
+                                                               "%s sending route-refresh (EoRR) for %s/%s",
+                                                               peer->host,
+                                                               afi2str(afi),
+                                                               safi2str(safi));
+                                       }
+                               }
+
                                if (CHECK_FLAG(peer->cap,
                                               PEER_CAP_RESTART_RCV)) {
                                        if (!(PAF_SUBGRP(paf))->t_coalesce
@@ -809,7 +848,7 @@ void bgp_notify_send(struct peer *peer, uint8_t code, uint8_t sub_code)
  */
 void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi,
                            uint8_t orf_type, uint8_t when_to_refresh,
-                           int remove)
+                           int remove, uint8_t subtype)
 {
        struct stream *s;
        struct bgp_filter *filter;
@@ -835,7 +874,10 @@ void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi,
 
        /* Encode Route Refresh message. */
        stream_putw(s, pkt_afi);
-       stream_putc(s, 0);
+       if (subtype)
+               stream_putc(s, subtype);
+       else
+               stream_putc(s, 0);
        stream_putc(s, pkt_safi);
 
        if (orf_type == ORF_TYPE_PREFIX || orf_type == ORF_TYPE_PREFIX_OLD)
@@ -1393,13 +1435,8 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
            || peer->afc_nego[AFI_IP][SAFI_ENCAP]) {
                if (peer->nexthop.v4.s_addr == INADDR_ANY) {
 #if defined(HAVE_CUMULUS)
-                       flog_err(
-                               EC_BGP_SND_FAIL,
-                               "%s: No local IPv4 addr resetting connection, fd %d",
-                               peer->host, peer->fd);
-                       bgp_notify_send(peer, BGP_NOTIFY_CEASE,
-                                       BGP_NOTIFY_SUBCODE_UNSPECIFIC);
-                       return BGP_Stop;
+                       zlog_warn("%s: No local IPv4 addr, BGP routing may not work",
+                                 peer->host);
 #endif
                }
        }
@@ -1410,13 +1447,8 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
            || peer->afc_nego[AFI_IP6][SAFI_ENCAP]) {
                if (IN6_IS_ADDR_UNSPECIFIED(&peer->nexthop.v6_global)) {
 #if defined(HAVE_CUMULUS)
-                       flog_err(
-                               EC_BGP_SND_FAIL,
-                               "%s: No local IPv6 addr resetting connection, fd %d",
-                               peer->host, peer->fd);
-                       bgp_notify_send(peer, BGP_NOTIFY_CEASE,
-                                       BGP_NOTIFY_SUBCODE_UNSPECIFIC);
-                       return BGP_Stop;
+                       zlog_warn("%s: No local IPv6 address, BGP routing may not work",
+                                 peer->host);
 #endif
                }
        }
@@ -1463,6 +1495,29 @@ static int bgp_keepalive_receive(struct peer *peer, bgp_size_t size)
        return Receive_KEEPALIVE_message;
 }
 
+static int bgp_refresh_stalepath_timer_expire(struct thread *thread)
+{
+       struct peer_af *paf;
+
+       paf = THREAD_ARG(thread);
+
+       afi_t afi = paf->afi;
+       safi_t safi = paf->safi;
+       struct peer *peer = paf->peer;
+
+       peer->t_refresh_stalepath = NULL;
+
+       if (peer->nsf[afi][safi])
+               bgp_clear_stale_route(peer, afi, safi);
+
+       if (bgp_debug_neighbor_events(peer))
+               zlog_debug("%s: route-refresh (BoRR) timer for %s/%s expired",
+                          peer->host, afi2str(afi), safi2str(safi));
+
+       bgp_timer_set(peer);
+
+       return 0;
+}
 
 /**
  * Process BGP UPDATE message for peer.
@@ -1891,6 +1946,9 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
        struct peer_af *paf;
        struct update_group *updgrp;
        struct peer *updgrp_peer;
+       uint8_t subtype;
+       bgp_size_t msg_length =
+               size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE);
 
        /* If peer does not have the capability, send notification. */
        if (!CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_ADV)) {
@@ -1918,14 +1976,9 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
 
        /* Parse packet. */
        pkt_afi = stream_getw(s);
-       (void)stream_getc(s);
+       subtype = stream_getc(s);
        pkt_safi = stream_getc(s);
 
-       if (bgp_debug_update(peer, NULL, NULL, 0))
-               zlog_debug("%s rcvd REFRESH_REQ for afi/safi: %s/%s",
-                          peer->host, iana_afi2str(pkt_afi),
-                          iana_safi2str(pkt_safi));
-
        /* Convert AFI, SAFI to internal values and check. */
        if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
                zlog_info(
@@ -1941,8 +1994,34 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
                uint8_t orf_type;
                uint16_t orf_len;
 
-               if (size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE)
-                   < 5) {
+               if (subtype) {
+                       /* If the length, excluding the fixed-size message
+                        * header, of the received ROUTE-REFRESH message with
+                        * Message Subtype 1 and 2 is not 4, then the BGP
+                        * speaker MUST send a NOTIFICATION message with the
+                        * Error Code of "ROUTE-REFRESH Message Error" and the
+                        * subcode of "Invalid Message Length".
+                        */
+                       if (msg_length != 4) {
+                               zlog_err(
+                                       "%s Enhanced Route Refresh message length error",
+                                       peer->host);
+                               bgp_notify_send(
+                                       peer, BGP_NOTIFY_ROUTE_REFRESH_ERR,
+                                       BGP_NOTIFY_ROUTE_REFRESH_INVALID_MSG_LEN);
+                       }
+
+                       /* When the BGP speaker receives a ROUTE-REFRESH message
+                        * with a "Message Subtype" field other than 0, 1, or 2,
+                        * it MUST ignore the received ROUTE-REFRESH message.
+                        */
+                       if (subtype > 2)
+                               zlog_err(
+                                       "%s Enhanced Route Refresh invalid subtype",
+                                       peer->host);
+               }
+
+               if (msg_length < 5) {
                        zlog_info("%s ORF route refresh length error",
                                  peer->host);
                        bgp_notify_send(peer, BGP_NOTIFY_CEASE,
@@ -2126,6 +2205,11 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
                                peer->orf_plist[afi][safi];
                }
 
+               /* Avoid supressing duplicate routes later
+                * when processing in subgroup_announce_table().
+                */
+               SET_FLAG(paf->subgroup->sflags, SUBGRP_STATUS_FORCE_UPDATES);
+
                /* If the peer is configured for default-originate clear the
                 * SUBGRP_STATUS_DEFAULT_ORIGINATE flag so that we will
                 * re-advertise the
@@ -2137,6 +2221,124 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
                                   SUBGRP_STATUS_DEFAULT_ORIGINATE);
        }
 
+       if (subtype == BGP_ROUTE_REFRESH_BORR) {
+               /* A BGP speaker that has received the Graceful Restart
+                * Capability from its neighbor MUST ignore any BoRRs for
+                * an <AFI, SAFI> from the neighbor before the speaker
+                * receives the EoR for the given <AFI, SAFI> from the
+                * neighbor.
+                */
+               if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)
+                   && !CHECK_FLAG(peer->af_sflags[afi][safi],
+                                  PEER_STATUS_EOR_RECEIVED)) {
+                       if (bgp_debug_neighbor_events(peer))
+                               zlog_debug(
+                                       "%s rcvd route-refresh (BoRR) for %s/%s before EoR",
+                                       peer->host, afi2str(afi),
+                                       safi2str(safi));
+                       return BGP_PACKET_NOOP;
+               }
+
+               if (peer->t_refresh_stalepath) {
+                       if (bgp_debug_neighbor_events(peer))
+                               zlog_debug(
+                                       "%s rcvd route-refresh (BoRR) for %s/%s, whereas BoRR already received",
+                                       peer->host, afi2str(afi),
+                                       safi2str(safi));
+                       return BGP_PACKET_NOOP;
+               }
+
+               SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_BORR_RECEIVED);
+               UNSET_FLAG(peer->af_sflags[afi][safi],
+                          PEER_STATUS_EORR_RECEIVED);
+
+               /* When a BGP speaker receives a BoRR message from
+                * a peer, it MUST mark all the routes with the given
+                * Address Family Identifier and Subsequent Address
+                * Family Identifier, <AFI, SAFI> [RFC2918], from
+                * that peer as stale.
+                */
+               if (peer_active_nego(peer)) {
+                       SET_FLAG(peer->af_sflags[afi][safi],
+                                PEER_STATUS_ENHANCED_REFRESH);
+                       bgp_set_stale_route(peer, afi, safi);
+               }
+
+               if (peer->status == Established)
+                       thread_add_timer(bm->master,
+                                        bgp_refresh_stalepath_timer_expire,
+                                        paf, peer->bgp->stalepath_time,
+                                        &peer->t_refresh_stalepath);
+
+               if (bgp_debug_neighbor_events(peer))
+                       zlog_debug(
+                               "%s rcvd route-refresh (BoRR) for %s/%s, triggering timer for %u seconds",
+                               peer->host, afi2str(afi), safi2str(safi),
+                               peer->bgp->stalepath_time);
+       } else if (subtype == BGP_ROUTE_REFRESH_EORR) {
+               if (!peer->t_refresh_stalepath) {
+                       zlog_err(
+                               "%s rcvd route-refresh (EoRR) for %s/%s, whereas no BoRR received",
+                               peer->host, afi2str(afi), safi2str(safi));
+                       return BGP_PACKET_NOOP;
+               }
+
+               BGP_TIMER_OFF(peer->t_refresh_stalepath);
+
+               SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EORR_RECEIVED);
+               UNSET_FLAG(peer->af_sflags[afi][safi],
+                          PEER_STATUS_BORR_RECEIVED);
+
+               if (bgp_debug_neighbor_events(peer))
+                       zlog_debug(
+                               "%s rcvd route-refresh (EoRR) for %s/%s, stopping BoRR timer",
+                               peer->host, afi2str(afi), safi2str(safi));
+
+               if (peer->nsf[afi][safi])
+                       bgp_clear_stale_route(peer, afi, safi);
+       } else {
+               if (bgp_debug_neighbor_events(peer))
+                       zlog_debug("%s rcvd route-refresh (REQUEST) for %s/%s",
+                                  peer->host, afi2str(afi), safi2str(safi));
+
+               /* In response to a "normal route refresh request" from the
+                * peer, the speaker MUST send a BoRR message.
+                */
+               if (CHECK_FLAG(peer->cap, PEER_CAP_ENHANCED_RR_RCV)) {
+                       /* For a BGP speaker that supports the BGP Graceful
+                        * Restart, it MUST NOT send a BoRR for an <AFI, SAFI>
+                        * to a neighbor before it sends the EoR for the
+                        * <AFI, SAFI> to the neighbor.
+                        */
+                       if (!CHECK_FLAG(peer->af_sflags[afi][safi],
+                                       PEER_STATUS_EOR_SEND)) {
+                               if (bgp_debug_neighbor_events(peer))
+                                       zlog_debug(
+                                               "%s rcvd route-refresh (REQUEST) for %s/%s before EoR",
+                                               peer->host, afi2str(afi),
+                                               safi2str(safi));
+                               return BGP_PACKET_NOOP;
+                       }
+
+                       bgp_route_refresh_send(peer, afi, safi, 0, 0, 0,
+                                              BGP_ROUTE_REFRESH_BORR);
+
+                       if (bgp_debug_neighbor_events(peer))
+                               zlog_debug(
+                                       "%s sending route-refresh (BoRR) for %s/%s",
+                                       peer->host, afi2str(afi),
+                                       safi2str(safi));
+
+                       /* Set flag Ready-To-Send to know when we can send EoRR
+                        * message.
+                        */
+                       SET_FLAG(peer->af_sflags[afi][safi],
+                                PEER_STATUS_BORR_SEND);
+                       UNSET_FLAG(peer->af_sflags[afi][safi],
+                                  PEER_STATUS_EORR_SEND);
+               }
+       }
+
        /* Perform route refreshment to the peer */
        bgp_announce_route(peer, afi, safi);
 
@@ -2229,12 +2431,13 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
                        /* Address family check.  */
                        if (bgp_debug_neighbor_events(peer))
                                zlog_debug(
-                                       "%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u",
+                                       "%s CAPABILITY has %s MP_EXT CAP for afi/safi: %s/%s",
                                        peer->host,
                                        action == CAPABILITY_ACTION_SET
                                                ? "Advertising"
                                                : "Removing",
-                                       pkt_afi, pkt_safi);
+                                       iana_afi2str(pkt_afi),
+                                       iana_safi2str(pkt_safi));
 
                        if (action == CAPABILITY_ACTION_SET) {
                                peer->afc_recv[afi][safi] = 1;
index e83f7d950c8f172aa6b38f419bfc1fcc932d290c..525859a2da68a777abc0a229d9da8766299c75a9 100644 (file)
@@ -62,8 +62,9 @@ extern void bgp_open_send(struct peer *);
 extern void bgp_notify_send(struct peer *, uint8_t, uint8_t);
 extern void bgp_notify_send_with_data(struct peer *, uint8_t, uint8_t,
                                      uint8_t *, size_t);
-extern void bgp_route_refresh_send(struct peer *, afi_t, safi_t, uint8_t,
-                                  uint8_t, int);
+extern void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi,
+                                  uint8_t orf_type, uint8_t when_to_refresh,
+                                  int remove, uint8_t subtype);
 extern void bgp_capability_send(struct peer *, afi_t, safi_t, int, int);
 
 extern int bgp_capability_receive(struct peer *, bgp_size_t);
index a3f1eb8401ff2ec1cac69083042ce5e123626417..4f22f5bcfeb9a93b526453bf44d7e164cf9a946a 100644 (file)
@@ -754,7 +754,7 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
                                     struct bgp_pbr_entry_main *api)
 {
        int ret;
-       int i, action_count = 0;
+       uint32_t i, action_count = 0;
        struct ecommunity *ecom;
        struct ecommunity_val *ecom_eval;
        struct bgp_pbr_entry_action *api_action;
index 87e8feb3bf7bda029fc1bc6a0e28eea9f694dea3..c4ab223b7f5956b54904638b2170e50e95f99a57 100644 (file)
@@ -96,7 +96,7 @@
 /* Extern from bgp_dump.c */
 extern const char *bgp_origin_str[];
 extern const char *bgp_origin_long_str[];
-const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
+
 /* PMSI strings. */
 #define PMSI_TNLTYPE_STR_NO_INFO "No info"
 #define PMSI_TNLTYPE_STR_DEFAULT PMSI_TNLTYPE_STR_NO_INFO
@@ -208,9 +208,6 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra)
                return;
 
        e = *extra;
-       if (e->damp_info)
-               bgp_damp_info_free(e->damp_info, 0, e->damp_info->afi,
-                                  e->damp_info->safi);
 
        e->damp_info = NULL;
        if (e->parent) {
@@ -244,6 +241,9 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra)
        if (e->aggr_suppressors)
                list_delete(&e->aggr_suppressors);
 
+       if (e->es_info)
+               bgp_evpn_path_es_info_free(e->es_info);
+
        if ((*extra)->bgp_fs_iprule)
                list_delete(&((*extra)->bgp_fs_iprule));
        if ((*extra)->bgp_fs_pbr)
@@ -2752,7 +2752,10 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
                                                == BGP_ROUTE_REDISTRIBUTE) {
                                        if (CHECK_FLAG(
                                                    dest->flags,
-                                                   BGP_NODE_REGISTERED_FOR_LABEL))
+                                                   BGP_NODE_REGISTERED_FOR_LABEL)
+                                           || CHECK_FLAG(
+                                                   dest->flags,
+                                                   BGP_NODE_LABEL_REQUESTED))
                                                bgp_unregister_for_label(dest);
                                        label_ntop(MPLS_LABEL_IMPLICIT_NULL, 1,
                                                   &dest->local_label);
@@ -2762,10 +2765,13 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
                                                               new_select);
                        }
                } else if (CHECK_FLAG(dest->flags,
-                                     BGP_NODE_REGISTERED_FOR_LABEL)) {
+                                     BGP_NODE_REGISTERED_FOR_LABEL)
+                          || CHECK_FLAG(dest->flags,
+                                        BGP_NODE_LABEL_REQUESTED)) {
                        bgp_unregister_for_label(dest);
                }
-       } else if (CHECK_FLAG(dest->flags, BGP_NODE_REGISTERED_FOR_LABEL)) {
+       } else if (CHECK_FLAG(dest->flags, BGP_NODE_REGISTERED_FOR_LABEL)
+                  || CHECK_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED)) {
                bgp_unregister_for_label(dest);
        }
 
@@ -3322,14 +3328,16 @@ static void bgp_rib_withdraw(struct bgp_dest *dest, struct bgp_path_info *pi,
        /* apply dampening, if result is suppressed, we'll be retaining
         * the bgp_path_info in the RIB for historical reference.
         */
-       if (CHECK_FLAG(peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
-           && peer->sort == BGP_PEER_EBGP)
-               if ((bgp_damp_withdraw(pi, dest, afi, safi, 0))
-                   == BGP_DAMP_SUPPRESSED) {
-                       bgp_aggregate_decrement(peer->bgp, p, pi, afi,
-                                               safi);
-                       return;
+       if (peer->sort == BGP_PEER_EBGP) {
+               if (get_active_bdc_from_pi(pi, afi, safi)) {
+                       if (bgp_damp_withdraw(pi, dest, afi, safi, 0)
+                           == BGP_DAMP_SUPPRESSED) {
+                               bgp_aggregate_decrement(peer->bgp, p, pi, afi,
+                                                       safi);
+                               return;
+                       }
                }
+       }
 
 #ifdef ENABLE_BGP_VNC
        if (safi == SAFI_MPLS_VPN) {
@@ -3754,8 +3762,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                    && (overlay_index_equal(
                               afi, pi,
                               evpn == NULL ? NULL : &evpn->gw_ip))) {
-                       if (CHECK_FLAG(bgp->af_flags[afi][safi],
-                                      BGP_CONFIG_DAMPENING)
+                       if (get_active_bdc_from_pi(pi, afi, safi)
                            && peer->sort == BGP_PEER_EBGP
                            && CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) {
                                if (bgp_debug_update(peer, p, NULL, 1)) {
@@ -3849,11 +3856,11 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                bgp_aggregate_decrement(bgp, p, pi, afi, safi);
 
                /* Update bgp route dampening information.  */
-               if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
+               if (get_active_bdc_from_pi(pi, afi, safi)
                    && peer->sort == BGP_PEER_EBGP) {
                        /* This is implicit withdraw so we should update
-                          dampening
-                          information.  */
+                        * dampening information.
+                        */
                        if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY))
                                bgp_damp_withdraw(pi, dest, afi, safi, 1);
                }
@@ -3976,7 +3983,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
 #endif
 
                /* Update bgp route dampening information.  */
-               if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
+               if (get_active_bdc_from_pi(pi, afi, safi)
                    && peer->sort == BGP_PEER_EBGP) {
                        /* Now we do normal update dampening.  */
                        ret = bgp_damp_update(pi, dest, afi, safi);
@@ -4592,8 +4599,10 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data)
                        continue;
 
                /* graceful restart STALE flag set. */
-               if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)
-                   && peer->nsf[afi][safi]
+               if (((CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)
+                     && peer->nsf[afi][safi])
+                    || CHECK_FLAG(peer->af_sflags[afi][safi],
+                                  PEER_STATUS_ENHANCED_REFRESH))
                    && !CHECK_FLAG(pi->flags, BGP_PATH_STALE)
                    && !CHECK_FLAG(pi->flags, BGP_PATH_UNUSEABLE))
                        bgp_path_info_set_flag(dest, pi, BGP_PATH_STALE);
@@ -4844,7 +4853,7 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
        struct bgp_path_info *pi;
        struct bgp_table *table;
 
-       if (safi == SAFI_MPLS_VPN) {
+       if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) {
                for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest;
                     dest = bgp_route_next(dest)) {
                        struct bgp_dest *rm;
@@ -4883,6 +4892,81 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
        }
 }
 
+void bgp_set_stale_route(struct peer *peer, afi_t afi, safi_t safi)
+{
+       struct bgp_dest *dest, *ndest;
+       struct bgp_path_info *pi;
+       struct bgp_table *table;
+
+       if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) {
+               for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest;
+                    dest = bgp_route_next(dest)) {
+                       table = bgp_dest_get_bgp_table_info(dest);
+                       if (!table)
+                               continue;
+
+                       for (ndest = bgp_table_top(table); ndest;
+                            ndest = bgp_route_next(ndest)) {
+                               for (pi = bgp_dest_get_bgp_path_info(ndest); pi;
+                                    pi = pi->next) {
+                                       if (pi->peer != peer)
+                                               continue;
+
+                                       if ((CHECK_FLAG(
+                                                   peer->af_sflags[afi][safi],
+                                                   PEER_STATUS_ENHANCED_REFRESH))
+                                           && !CHECK_FLAG(pi->flags,
+                                                          BGP_PATH_STALE)
+                                           && !CHECK_FLAG(
+                                                      pi->flags,
+                                                      BGP_PATH_UNUSEABLE)) {
+                                               if (bgp_debug_neighbor_events(
+                                                           peer))
+                                                       zlog_debug(
+                                                               "%s: route-refresh for %s/%s, marking prefix %pFX as stale",
+                                                               peer->host,
+                                                               afi2str(afi),
+                                                               safi2str(safi),
+                                                               bgp_dest_get_prefix(
+                                                                       ndest));
+
+                                               bgp_path_info_set_flag(
+                                                       ndest, pi,
+                                                       BGP_PATH_STALE);
+                                       }
+                               }
+                       }
+               }
+       } else {
+               for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest;
+                    dest = bgp_route_next(dest)) {
+                       for (pi = bgp_dest_get_bgp_path_info(dest); pi;
+                            pi = pi->next) {
+                               if (pi->peer != peer)
+                                       continue;
+
+                               if ((CHECK_FLAG(peer->af_sflags[afi][safi],
+                                               PEER_STATUS_ENHANCED_REFRESH))
+                                   && !CHECK_FLAG(pi->flags, BGP_PATH_STALE)
+                                   && !CHECK_FLAG(pi->flags,
+                                                  BGP_PATH_UNUSEABLE)) {
+                                       if (bgp_debug_neighbor_events(peer))
+                                               zlog_debug(
+                                                       "%s: route-refresh for %s/%s, marking prefix %pFX as stale",
+                                                       peer->host,
+                                                       afi2str(afi),
+                                                       safi2str(safi),
+                                                       bgp_dest_get_prefix(
+                                                               dest));
+
+                                       bgp_path_info_set_flag(dest, pi,
+                                                              BGP_PATH_STALE);
+                               }
+                       }
+               }
+       }
+}
+
 bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter)
 {
        if (peer->sort == BGP_PEER_IBGP)
@@ -8069,6 +8153,62 @@ enum bgp_display_type {
        normal_list,
 };
 
+static const char *
+bgp_path_selection_reason2str(enum bgp_path_selection_reason reason)
+{
+       switch (reason) {
+       case bgp_path_selection_none:
+               return "Nothing to Select";
+       case bgp_path_selection_first:
+               return "First path received";
+       case bgp_path_selection_evpn_sticky_mac:
+               return "EVPN Sticky Mac";
+       case bgp_path_selection_evpn_seq:
+               return "EVPN sequence number";
+       case bgp_path_selection_evpn_lower_ip:
+               return "EVPN lower IP";
+       case bgp_path_selection_evpn_local_path:
+               return "EVPN local ES path";
+       case bgp_path_selection_evpn_non_proxy:
+               return "EVPN non proxy";
+       case bgp_path_selection_weight:
+               return "Weight";
+       case bgp_path_selection_local_pref:
+               return "Local Pref";
+       case bgp_path_selection_local_route:
+               return "Local Route";
+       case bgp_path_selection_confed_as_path:
+               return "Confederation based AS Path";
+       case bgp_path_selection_as_path:
+               return "AS Path";
+       case bgp_path_selection_origin:
+               return "Origin";
+       case bgp_path_selection_med:
+               return "MED";
+       case bgp_path_selection_peer:
+               return "Peer Type";
+       case bgp_path_selection_confed:
+               return "Confed Peer Type";
+       case bgp_path_selection_igp_metric:
+               return "IGP Metric";
+       case bgp_path_selection_older:
+               return "Older Path";
+       case bgp_path_selection_router_id:
+               return "Router ID";
+       case bgp_path_selection_cluster_length:
+               return "Cluser length";
+       case bgp_path_selection_stale:
+               return "Path Staleness";
+       case bgp_path_selection_local_configured:
+               return "Locally configured route";
+       case bgp_path_selection_neighbor_ip:
+               return "Neighbor IP";
+       case bgp_path_selection_default:
+               return "Nothing left to compare";
+       }
+       return "Invalid (internal error)";
+}
+
 /* Print the short form route status for a bgp_path_info */
 static void route_vty_short_status_out(struct vty *vty,
                                       struct bgp_path_info *path,
@@ -8097,8 +8237,12 @@ static void route_vty_short_status_out(struct vty *vty,
                if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED))
                        json_object_boolean_true_add(json_path, "damped");
 
-               if (CHECK_FLAG(path->flags, BGP_PATH_SELECTED))
+               if (CHECK_FLAG(path->flags, BGP_PATH_SELECTED)) {
                        json_object_boolean_true_add(json_path, "bestpath");
+                       json_object_string_add(json_path, "selectionReason",
+                                              bgp_path_selection_reason2str(
+                                                      path->net->reason));
+               }
 
                if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH))
                        json_object_boolean_true_add(json_path, "multipath");
@@ -8617,11 +8761,21 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
                vty_out(vty, "\n");
 
                if (safi == SAFI_EVPN) {
+                       struct bgp_path_es_info *path_es_info = NULL;
+
+                       if (path->extra)
+                               path_es_info = path->extra->es_info;
+
                        if (bgp_evpn_is_esi_valid(&attr->esi)) {
+                               /* XXX - add these params to the json out */
                                vty_out(vty, "%*s", 20, " ");
-                               vty_out(vty, "ESI:%s\n",
-                                               esi_to_str(&attr->esi,
-                                               esi_buf, sizeof(esi_buf)));
+                               vty_out(vty, "ESI:%s",
+                                       esi_to_str(&attr->esi, esi_buf,
+                                                  sizeof(esi_buf)));
+                               if (path_es_info && path_es_info->es)
+                                       vty_out(vty, " VNI: %u",
+                                               path_es_info->vni);
+                               vty_out(vty, "\n");
                        }
                        if (attr->flag &
                                ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) {
@@ -9241,64 +9395,10 @@ static void route_vty_out_tx_ids(struct vty *vty,
        }
 }
 
-static const char *bgp_path_selection_reason2str(
-       enum bgp_path_selection_reason reason)
-{
-       switch (reason) {
-       case bgp_path_selection_none:
-               return "Nothing to Select";
-       case bgp_path_selection_first:
-               return "First path received";
-       case bgp_path_selection_evpn_sticky_mac:
-               return "EVPN Sticky Mac";
-       case bgp_path_selection_evpn_seq:
-               return "EVPN sequence number";
-       case bgp_path_selection_evpn_lower_ip:
-               return "EVPN lower IP";
-       case bgp_path_selection_evpn_local_path:
-               return "EVPN local ES path";
-       case bgp_path_selection_evpn_non_proxy:
-               return "EVPN non proxy";
-       case bgp_path_selection_weight:
-               return "Weight";
-       case bgp_path_selection_local_pref:
-               return "Local Pref";
-       case bgp_path_selection_local_route:
-               return "Local Route";
-       case bgp_path_selection_confed_as_path:
-               return "Confederation based AS Path";
-       case bgp_path_selection_as_path:
-               return "AS Path";
-       case bgp_path_selection_origin:
-               return "Origin";
-       case bgp_path_selection_med:
-               return "MED";
-       case bgp_path_selection_peer:
-               return "Peer Type";
-       case bgp_path_selection_confed:
-               return "Confed Peer Type";
-       case bgp_path_selection_igp_metric:
-               return "IGP Metric";
-       case bgp_path_selection_older:
-               return "Older Path";
-       case bgp_path_selection_router_id:
-               return "Router ID";
-       case bgp_path_selection_cluster_length:
-               return "Cluser length";
-       case bgp_path_selection_stale:
-               return "Path Staleness";
-       case bgp_path_selection_local_configured:
-               return "Locally configured route";
-       case bgp_path_selection_neighbor_ip:
-               return "Neighbor IP";
-       case bgp_path_selection_default:
-               return "Nothing left to compare";
-       }
-       return "Invalid (internal error)";
-}
-
 static void route_vty_out_detail_es_info(struct vty *vty,
-                         struct attr *attr, json_object *json_path)
+                                        struct bgp_path_info *pi,
+                                        struct attr *attr,
+                                        json_object *json_path)
 {
        char esi_buf[ESI_STR_LEN];
        bool es_local = !!CHECK_FLAG(attr->es_flags, ATTR_ES_IS_LOCAL);
@@ -9308,7 +9408,6 @@ static void route_vty_out_detail_es_info(struct vty *vty,
                        ATTR_ES_PEER_ACTIVE);
        bool peer_proxy = !!CHECK_FLAG(attr->es_flags,
                        ATTR_ES_PEER_PROXY);
-
        esi_to_str(&attr->esi, esi_buf, sizeof(esi_buf));
        if (json_path) {
                json_object *json_es_info = NULL;
@@ -9843,7 +9942,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
 
        if (safi == SAFI_EVPN &&
                        bgp_evpn_is_esi_valid(&attr->esi)) {
-               route_vty_out_detail_es_info(vty, attr, json_path);
+               route_vty_out_detail_es_info(vty, path, attr, json_path);
        }
 
        /* Line 3 display Origin, Med, Locpref, Weight, Tag, valid,
@@ -10111,7 +10210,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
        }
 
        if (path->extra && path->extra->damp_info)
-               bgp_damp_info_vty(vty, path, afi, safi, json_path);
+               bgp_damp_info_vty(vty, bgp, path, afi, safi, json_path);
 
        /* Remote Label */
        if (path->extra && bgp_is_valid_label(&path->extra->label[0])
@@ -10243,6 +10342,24 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
                                str, label2vni(&attr->label));
        }
 
+       /* Output some debug about internal state of the dest flags */
+       if (json_paths) {
+               if (CHECK_FLAG(bn->flags, BGP_NODE_PROCESS_SCHEDULED))
+                       json_object_boolean_true_add(json_path, "processScheduled");
+               if (CHECK_FLAG(bn->flags, BGP_NODE_USER_CLEAR))
+                       json_object_boolean_true_add(json_path, "userCleared");
+               if (CHECK_FLAG(bn->flags, BGP_NODE_LABEL_CHANGED))
+                       json_object_boolean_true_add(json_path, "labelChanged");
+               if (CHECK_FLAG(bn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
+                       json_object_boolean_true_add(json_path, "registeredForLabel");
+               if (CHECK_FLAG(bn->flags, BGP_NODE_SELECT_DEFER))
+                       json_object_boolean_true_add(json_path, "selectDefered");
+               if (CHECK_FLAG(bn->flags, BGP_NODE_FIB_INSTALLED))
+                       json_object_boolean_true_add(json_path, "fibInstalled");
+               if (CHECK_FLAG(bn->flags, BGP_NODE_FIB_INSTALL_PENDING))
+                       json_object_boolean_true_add(json_path, "fibPending");
+       }
+
        /* We've constructed the json object for this path, add it to the json
         * array of paths
         */
@@ -11721,10 +11838,6 @@ DEFPY (show_ip_bgp_json,
                                      ? AFI_IP
                                      : AFI_IP6;
                        FOREACH_SAFI (safi) {
-                               if (strmatch(get_afi_safi_str(afi, safi, true),
-                                            "Unknown"))
-                                       continue;
-
                                if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
                                        continue;
 
@@ -11755,10 +11868,6 @@ DEFPY (show_ip_bgp_json,
                } else {
                        /* show <ip> bgp all: for each AFI and SAFI*/
                        FOREACH_AFI_SAFI (afi, safi) {
-                               if (strmatch(get_afi_safi_str(afi, safi, true),
-                                            "Unknown"))
-                                       continue;
-
                                if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
                                        continue;
 
@@ -13300,10 +13409,6 @@ DEFPY (show_ip_bgp_instance_neighbor_advertised_route,
                afi = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP) ? AFI_IP
                                                                  : AFI_IP6;
                FOREACH_SAFI (safi) {
-                       if (strmatch(get_afi_safi_str(afi, safi, true),
-                                    "Unknown"))
-                               continue;
-
                        if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
                                continue;
 
@@ -13323,10 +13428,6 @@ DEFPY (show_ip_bgp_instance_neighbor_advertised_route,
                }
        } else {
                FOREACH_AFI_SAFI (afi, safi) {
-                       if (strmatch(get_afi_safi_str(afi, safi, true),
-                                    "Unknown"))
-                               continue;
-
                        if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
                                continue;
 
@@ -13684,7 +13785,7 @@ uint8_t bgp_distance_apply(const struct prefix *p, struct bgp_path_info *pinfo,
                           afi_t afi, safi_t safi, struct bgp *bgp)
 {
        struct bgp_dest *dest;
-       struct prefix q;
+       struct prefix q = {0};
        struct peer *peer;
        struct bgp_distance *bdistance;
        struct access_list *alist;
@@ -13698,8 +13799,13 @@ uint8_t bgp_distance_apply(const struct prefix *p, struct bgp_path_info *pinfo,
        if (pinfo->attr->distance)
                return pinfo->attr->distance;
 
-       /* Check source address. */
-       sockunion2hostprefix(&peer->su, &q);
+       /* Check source address.
+        * Note: for aggregate route, peer can have unspec af type.
+        */
+       if (pinfo->sub_type != BGP_ROUTE_AGGREGATE
+           && !sockunion2hostprefix(&peer->su, &q))
+               return 0;
+
        dest = bgp_node_match(bgp_distance_table[afi][safi], &q);
        if (dest) {
                bdistance = bgp_dest_get_bgp_distance_info(dest);
@@ -13732,10 +13838,14 @@ uint8_t bgp_distance_apply(const struct prefix *p, struct bgp_path_info *pinfo,
                if (bgp->distance_ebgp[afi][safi])
                        return bgp->distance_ebgp[afi][safi];
                return ZEBRA_EBGP_DISTANCE_DEFAULT;
-       } else {
+       } else if (peer->sort == BGP_PEER_IBGP) {
                if (bgp->distance_ibgp[afi][safi])
                        return bgp->distance_ibgp[afi][safi];
                return ZEBRA_IBGP_DISTANCE_DEFAULT;
+       } else {
+               if (bgp->distance_local[afi][safi])
+                       return bgp->distance_local[afi][safi];
+               return ZEBRA_IBGP_DISTANCE_DEFAULT;
        }
 }
 
@@ -14050,7 +14160,8 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
                                        if (pi->extra && pi->extra->damp_info) {
                                                pi_temp = pi->next;
                                                bgp_damp_info_free(
-                                                       pi->extra->damp_info,
+                                                       &pi->extra->damp_info,
+                                                       &bgp->damp[afi][safi],
                                                        1, afi, safi);
                                                pi = pi_temp;
                                        } else
@@ -14072,7 +14183,8 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
                                        if (pi->extra && pi->extra->damp_info) {
                                                pi_temp = pi->next;
                                                bgp_damp_info_free(
-                                                       pi->extra->damp_info,
+                                                       &pi->extra->damp_info,
+                                                       &bgp->damp[afi][safi],
                                                        1, afi, safi);
                                                pi = pi_temp;
                                        } else
@@ -14095,7 +14207,9 @@ DEFUN (clear_ip_bgp_dampening,
        BGP_STR
        "Clear route flap dampening information\n")
 {
-       bgp_damp_info_clean(AFI_IP, SAFI_UNICAST);
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+       bgp_damp_info_clean(&bgp->damp[AFI_IP][SAFI_UNICAST], AFI_IP,
+                           SAFI_UNICAST);
        return CMD_SUCCESS;
 }
 
index 0b76d7504b5f10eaef3fd477f8eb34f018ebb74e..bdbf4743ab595940c7da450d734716c8ed48c2f5 100644 (file)
@@ -102,6 +102,19 @@ enum bgp_show_adj_route_type {
 #define BGP_NLRI_PARSE_ERROR_EVPN_TYPE1_SIZE -15
 #define BGP_NLRI_PARSE_ERROR -32
 
+/* MAC-IP/type-2 path_info in the VNI routing table is linked to the
+ * destination ES
+ */
+struct bgp_path_es_info {
+       /* back pointer to the route */
+       struct bgp_path_info *pi;
+       vni_t vni;
+       /* destination ES */
+       struct bgp_evpn_es *es;
+       /* memory used for linking the path to the destination ES */
+       struct listnode es_listnode;
+};
+
 /* Ancillary information to struct bgp_path_info,
  * used for uncommonly used data (aggregation, MPLS, etc.)
  * and lazily allocated to save memory.
@@ -188,6 +201,8 @@ struct bgp_path_info_extra {
        struct list *bgp_fs_pbr;
        /* presence of FS pbr iprule based entry */
        struct list *bgp_fs_iprule;
+       /* Destination Ethernet Segment links for EVPN MH */
+       struct bgp_path_es_info *es_info;
 };
 
 struct bgp_path_info {
@@ -560,6 +575,7 @@ extern void bgp_clear_route(struct peer *, afi_t, safi_t);
 extern void bgp_clear_route_all(struct peer *);
 extern void bgp_clear_adj_in(struct peer *, afi_t, safi_t);
 extern void bgp_clear_stale_route(struct peer *, afi_t, safi_t);
+extern void bgp_set_stale_route(struct peer *peer, afi_t afi, safi_t safi);
 extern bool bgp_outbound_policy_exists(struct peer *, struct bgp_filter *);
 extern bool bgp_inbound_policy_exists(struct peer *, struct bgp_filter *);
 
index 637eaca397740fa6e5b29ec273eef3a6dd42efae..ceaf8c0963255fdb7740b1f1aa7ccfae60573313 100644 (file)
@@ -65,6 +65,7 @@
 #include "bgpd/bgp_flowspec_util.h"
 #include "bgpd/bgp_encap_types.h"
 #include "bgpd/bgp_mpath.h"
+#include "bgpd/bgp_script.h"
 
 #ifdef ENABLE_BGP_VNC
 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
@@ -337,99 +338,138 @@ static const struct route_map_rule_cmd route_match_peer_cmd = {
        route_match_peer_free
 };
 
-#if defined(HAVE_LUA)
-static enum route_map_cmd_result_t
-route_match_command(void *rule, const struct prefix *prefix, void *object)
-{
-       int status = RMAP_NOMATCH;
-       u_int32_t locpref = 0;
-       u_int32_t newlocpref = 0;
-       enum lua_rm_status lrm_status;
-       struct bgp_path_info *path = (struct bgp_path_info *)object;
-       lua_State *L = lua_initialize("/etc/frr/lua.scr");
-
-       if (L == NULL)
-               return status;
+#ifdef HAVE_SCRIPTING
 
+enum frrlua_rm_status {
        /*
-        * Setup the prefix information to pass in
+        * Script function run failure.  This will translate into a deny
         */
-       lua_setup_prefix_table(L, prefix);
-
-       zlog_debug("Set up prefix table");
+       LUA_RM_FAILURE = 0,
        /*
-        * Setup the bgp_path_info information
+        * No Match was found for the route map function
         */
-       lua_newtable(L);
-       lua_pushinteger(L, path->attr->med);
-       lua_setfield(L, -2, "metric");
-       lua_pushinteger(L, path->attr->nh_ifindex);
-       lua_setfield(L, -2, "ifindex");
-       lua_pushstring(L, path->attr->aspath->str);
-       lua_setfield(L, -2, "aspath");
-       lua_pushinteger(L, path->attr->local_pref);
-       lua_setfield(L, -2, "localpref");
-       zlog_debug("%s %d", path->attr->aspath->str, path->attr->nh_ifindex);
-       lua_setglobal(L, "nexthop");
-
-       zlog_debug("Set up nexthop information");
+       LUA_RM_NOMATCH,
        /*
-        * Run the rule
+        * Match was found but no changes were made to the incoming data.
         */
-       lrm_status = lua_run_rm_rule(L, rule);
-       switch (lrm_status) {
+       LUA_RM_MATCH,
+       /*
+        * Match was found and data was modified, so figure out what changed
+        */
+       LUA_RM_MATCH_AND_CHANGE,
+};
+
+static enum route_map_cmd_result_t
+route_match_script(void *rule, const struct prefix *prefix, void *object)
+{
+       const char *scriptname = rule;
+       struct bgp_path_info *path = (struct bgp_path_info *)object;
+
+       struct frrscript *fs = frrscript_load(scriptname, NULL);
+
+       if (!fs) {
+               zlog_err("Issue loading script rule; defaulting to no match");
+               return RMAP_NOMATCH;
+       }
+
+       enum frrlua_rm_status status_failure = LUA_RM_FAILURE,
+                             status_nomatch = LUA_RM_NOMATCH,
+                             status_match = LUA_RM_MATCH,
+                             status_match_and_change = LUA_RM_MATCH_AND_CHANGE;
+
+       /* Make result values available */
+       struct frrscript_env env[] = {
+               {"integer", "RM_FAILURE", &status_failure},
+               {"integer", "RM_NOMATCH", &status_nomatch},
+               {"integer", "RM_MATCH", &status_match},
+               {"integer", "RM_MATCH_AND_CHANGE", &status_match_and_change},
+               {"integer", "action", &status_failure},
+               {"prefix", "prefix", prefix},
+               {"attr", "attributes", path->attr},
+               {"peer", "peer", path->peer},
+               {}};
+
+       struct frrscript_env results[] = {
+               {"integer", "action"},
+               {"attr", "attributes"},
+               {},
+       };
+
+       int result = frrscript_call(fs, env);
+
+       if (result) {
+               zlog_err("Issue running script rule; defaulting to no match");
+               return RMAP_NOMATCH;
+       }
+
+       enum frrlua_rm_status *lrm_status =
+               frrscript_get_result(fs, &results[0]);
+
+       int status = RMAP_NOMATCH;
+
+       switch (*lrm_status) {
        case LUA_RM_FAILURE:
-               zlog_debug("RM_FAILURE");
+               zlog_err(
+                       "Executing route-map match script '%s' failed; defaulting to no match",
+                       scriptname);
+               status = RMAP_NOMATCH;
                break;
        case LUA_RM_NOMATCH:
-               zlog_debug("RM_NOMATCH");
+               status = RMAP_NOMATCH;
                break;
        case LUA_RM_MATCH_AND_CHANGE:
-               zlog_debug("MATCH AND CHANGE");
-               lua_getglobal(L, "nexthop");
-               path->attr->med = get_integer(L, "metric");
-               /*
-                * This needs to be abstraced with the set function
-                */
+               status = RMAP_MATCH;
+               zlog_debug("Updating attribute based on script's values");
+
+               uint32_t locpref = 0;
+               struct attr *newattr = frrscript_get_result(fs, &results[1]);
+
+               path->attr->med = newattr->med;
+
                if (path->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))
                        locpref = path->attr->local_pref;
-               newlocpref = get_integer(L, "localpref");
-               if (newlocpref != locpref) {
-                       path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
-                       path->attr->local_pref = newlocpref;
+               if (locpref != newattr->local_pref) {
+                       SET_FLAG(path->attr->flag,
+                                ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF));
+                       path->attr->local_pref = newattr->local_pref;
                }
-               status = RMAP_MATCH;
+
+               aspath_free(newattr->aspath);
+               XFREE(MTYPE_TMP, newattr);
                break;
        case LUA_RM_MATCH:
-               zlog_debug("MATCH ONLY");
                status = RMAP_MATCH;
                break;
        }
-       lua_close(L);
+
+       XFREE(MTYPE_TMP, lrm_status);
+       frrscript_unload(fs);
+
        return status;
 }
 
-static void *route_match_command_compile(const char *arg)
+static void *route_match_script_compile(const char *arg)
 {
-       char *command;
+       char *scriptname;
+
+       scriptname = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
 
-       command = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
-       return command;
+       return scriptname;
 }
 
-static void
-route_match_command_free(void *rule)
+static void route_match_script_free(void *rule)
 {
        XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
 }
 
-static const struct route_map_rule_cmd route_match_command_cmd = {
-       "command",
-       route_match_command,
-       route_match_command_compile,
-       route_match_command_free
+static const struct route_map_rule_cmd route_match_script_cmd = {
+       "script",
+       route_match_script,
+       route_match_script_compile,
+       route_match_script_free
 };
-#endif
+
+#endif /* HAVE_SCRIPTING */
 
 /* `match ip address IP_ACCESS_LIST' */
 
@@ -3503,8 +3543,9 @@ static void bgp_route_map_process_peer(const char *rmap_name,
                                        zlog_debug(
                                                "Processing route_map %s update on peer %s (inbound, route-refresh)",
                                                rmap_name, peer->host);
-                               bgp_route_refresh_send(peer, afi, safi, 0, 0,
-                                                      0);
+                               bgp_route_refresh_send(
+                                       peer, afi, safi, 0, 0, 0,
+                                       BGP_ROUTE_REFRESH_NORMAL);
                        }
                }
        }
@@ -4095,30 +4136,29 @@ DEFUN (no_match_peer,
                                      RMAP_EVENT_MATCH_DELETED);
 }
 
-#if defined(HAVE_LUA)
-DEFUN (match_command,
-       match_command_cmd,
-       "match command WORD",
-       MATCH_STR
-       "Run a command to match\n"
-       "The command to run\n")
-{
-       return bgp_route_match_add(vty, "command", argv[2]->arg,
-                                  RMAP_EVENT_FILTER_ADDED);
-}
-
-DEFUN (no_match_command,
-       no_match_command_cmd,
-       "no match command WORD",
+#ifdef HAVE_SCRIPTING
+DEFUN (match_script,
+       match_script_cmd,
+       "[no] match script WORD",
        NO_STR
        MATCH_STR
-       "Run a command to match\n"
-       "The command to run\n")
+       "Execute script to determine match\n"
+       "The script name to run, without .lua; e.g. 'myroutemap' to run myroutemap.lua\n")
 {
-       return bgp_route_match_delete(vty, "command", argv[3]->arg,
-                                     RMAP_EVENT_FILTER_DELETED);
+       bool no = strmatch(argv[0]->text, "no");
+       int i = 0;
+       argv_find(argv, argc, "WORD", &i);
+       const char *script = argv[i]->arg;
+
+       if (no) {
+               return bgp_route_match_delete(vty, "script", script,
+                                             RMAP_EVENT_FILTER_DELETED);
+       } else {
+               return bgp_route_match_add(vty, "script", script,
+                                          RMAP_EVENT_FILTER_ADDED);
+       }
 }
-#endif
+#endif /* HAVE_SCRIPTING */
 
 /* match probability */
 DEFUN (match_probability,
@@ -5632,8 +5672,8 @@ void bgp_route_map_init(void)
 
        route_map_install_match(&route_match_peer_cmd);
        route_map_install_match(&route_match_local_pref_cmd);
-#if defined(HAVE_LUA)
-       route_map_install_match(&route_match_command_cmd);
+#ifdef HAVE_SCRIPTING
+       route_map_install_match(&route_match_script_cmd);
 #endif
        route_map_install_match(&route_match_ip_address_cmd);
        route_map_install_match(&route_match_ip_next_hop_cmd);
@@ -5797,9 +5837,8 @@ void bgp_route_map_init(void)
        install_element(RMAP_NODE, &no_set_ipv6_nexthop_prefer_global_cmd);
        install_element(RMAP_NODE, &set_ipv6_nexthop_peer_cmd);
        install_element(RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd);
-#if defined(HAVE_LUA)
-       install_element(RMAP_NODE, &match_command_cmd);
-       install_element(RMAP_NODE, &no_match_command_cmd);
+#ifdef HAVE_SCRIPTING
+       install_element(RMAP_NODE, &match_script_cmd);
 #endif
 }
 
index 24ee99bddbf20af06514cd226cc1a0abef13c80f..6bb33ff859d777bc1b76744bf7dfb30dac4248ac 100644 (file)
@@ -900,48 +900,47 @@ static int config_write(struct vty *vty)
        struct listnode *cache_node;
        struct cache *cache;
 
-       if (listcount(cache_list)) {
-               if (rpki_debug)
-                       vty_out(vty, "debug rpki\n");
-
-               vty_out(vty, "!\n");
-               vty_out(vty, "rpki\n");
-               vty_out(vty, "  rpki polling_period %d\n", polling_period);
-               for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
-                       switch (cache->type) {
-                               struct tr_tcp_config *tcp_config;
+       if (!listcount(cache_list))
+               return 0;
+
+       if (rpki_debug)
+               vty_out(vty, "debug rpki\n");
+
+       vty_out(vty, "!\n");
+       vty_out(vty, "rpki\n");
+       vty_out(vty, "  rpki polling_period %d\n", polling_period);
+       for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
+               switch (cache->type) {
+                       struct tr_tcp_config *tcp_config;
 #if defined(FOUND_SSH)
-                               struct tr_ssh_config *ssh_config;
+                       struct tr_ssh_config *ssh_config;
 #endif
-                       case TCP:
-                               tcp_config = cache->tr_config.tcp_config;
-                               vty_out(vty, "  rpki cache %s %s ",
-                                       tcp_config->host, tcp_config->port);
-                               break;
+               case TCP:
+                       tcp_config = cache->tr_config.tcp_config;
+                       vty_out(vty, "  rpki cache %s %s ", tcp_config->host,
+                               tcp_config->port);
+                       break;
 #if defined(FOUND_SSH)
-                       case SSH:
-                               ssh_config = cache->tr_config.ssh_config;
-                               vty_out(vty, "  rpki cache %s %u %s %s %s ",
-                                       ssh_config->host, ssh_config->port,
-                                       ssh_config->username,
-                                       ssh_config->client_privkey_path,
-                                       ssh_config->server_hostkey_path != NULL
-                                               ? ssh_config
-                                                         ->server_hostkey_path
-                                               : " ");
-                               break;
+               case SSH:
+                       ssh_config = cache->tr_config.ssh_config;
+                       vty_out(vty, "  rpki cache %s %u %s %s %s ",
+                               ssh_config->host, ssh_config->port,
+                               ssh_config->username,
+                               ssh_config->client_privkey_path,
+                               ssh_config->server_hostkey_path != NULL
+                                       ? ssh_config->server_hostkey_path
+                                       : " ");
+                       break;
 #endif
-                       default:
-                               break;
-                       }
-
-                       vty_out(vty, "preference %hhu\n", cache->preference);
+               default:
+                       break;
                }
-               vty_out(vty, "  exit\n");
-               return 1;
-       } else {
-               return 0;
+
+               vty_out(vty, "preference %hhu\n", cache->preference);
        }
+       vty_out(vty, "  exit\n");
+
+       return 1;
 }
 
 DEFUN_NOSH (rpki,
@@ -1275,53 +1274,49 @@ DEFUN (show_rpki_cache_connection,
        RPKI_OUTPUT_STRING
        "Show to which RPKI Cache Servers we have a connection\n")
 {
-       if (is_synchronized()) {
-               struct listnode *cache_node;
-               struct cache *cache;
-               struct rtr_mgr_group *group = get_connected_group();
-
-               if (!group) {
-                       vty_out(vty, "Cannot find a connected group.\n");
-                       return CMD_SUCCESS;
-               }
-               vty_out(vty, "Connected to group %d\n", group->preference);
-               for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
-                       if (cache->preference == group->preference) {
-                               struct tr_tcp_config *tcp_config;
+       if (!is_synchronized()) {
+               vty_out(vty, "No connection to RPKI cache server.\n");
+
+               return CMD_SUCCESS;
+       }
+
+       struct listnode *cache_node;
+       struct cache *cache;
+       struct rtr_mgr_group *group = get_connected_group();
+
+       if (!group) {
+               vty_out(vty, "Cannot find a connected group.\n");
+               return CMD_SUCCESS;
+       }
+       vty_out(vty, "Connected to group %d\n", group->preference);
+       for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
+               if (cache->preference == group->preference) {
+                       struct tr_tcp_config *tcp_config;
 #if defined(FOUND_SSH)
-                               struct tr_ssh_config *ssh_config;
+                       struct tr_ssh_config *ssh_config;
 #endif
 
-                               switch (cache->type) {
-                               case TCP:
-                                       tcp_config =
-                                               cache->tr_config.tcp_config;
-                                       vty_out(vty,
-                                               "rpki tcp cache %s %s pref %hhu\n",
-                                               tcp_config->host,
-                                               tcp_config->port,
-                                               cache->preference);
-                                       break;
+                       switch (cache->type) {
+                       case TCP:
+                               tcp_config = cache->tr_config.tcp_config;
+                               vty_out(vty, "rpki tcp cache %s %s pref %hhu\n",
+                                       tcp_config->host, tcp_config->port,
+                                       cache->preference);
+                               break;
 
 #if defined(FOUND_SSH)
-                               case SSH:
-                                       ssh_config =
-                                               cache->tr_config.ssh_config;
-                                       vty_out(vty,
-                                               "rpki ssh cache %s %u pref %hhu\n",
-                                               ssh_config->host,
-                                               ssh_config->port,
-                                               cache->preference);
-                                       break;
+                       case SSH:
+                               ssh_config = cache->tr_config.ssh_config;
+                               vty_out(vty, "rpki ssh cache %s %u pref %hhu\n",
+                                       ssh_config->host, ssh_config->port,
+                                       cache->preference);
+                               break;
 #endif
 
-                               default:
-                                       break;
-                               }
+                       default:
+                               break;
                        }
                }
-       } else {
-               vty_out(vty, "No connection to RPKI cache server.\n");
        }
 
        return CMD_SUCCESS;
diff --git a/bgpd/bgp_script.c b/bgpd/bgp_script.c
new file mode 100644 (file)
index 0000000..0cda192
--- /dev/null
@@ -0,0 +1,192 @@
+/* BGP scripting foo
+ * Copyright (C) 2020  NVIDIA Corporation
+ * Quentin Young
+ *
+ * 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>
+
+#ifdef HAVE_SCRIPTING
+
+#include "bgpd.h"
+#include "bgp_script.h"
+#include "bgp_debug.h"
+#include "bgp_aspath.h"
+#include "frratomic.h"
+#include "frrscript.h"
+#include "frrlua.h"
+
+static void lua_pushpeer(lua_State *L, const struct peer *peer)
+{
+       lua_newtable(L);
+       lua_pushinteger(L, peer->as);
+       lua_setfield(L, -2, "remote_as");
+       lua_pushinteger(L, peer->local_as);
+       lua_setfield(L, -2, "local_as");
+       lua_pushinaddr(L, &peer->remote_id);
+       lua_setfield(L, -2, "remote_id");
+       lua_pushinaddr(L, &peer->local_id);
+       lua_setfield(L, -2, "local_id");
+       lua_pushstring(L, lookup_msg(bgp_status_msg, peer->status, NULL));
+       lua_setfield(L, -2, "state");
+       lua_pushstring(L, peer->desc ? peer->desc : "");
+       lua_setfield(L, -2, "description");
+       lua_pushtimet(L, &peer->uptime);
+       lua_setfield(L, -2, "uptime");
+       lua_pushtimet(L, &peer->readtime);
+       lua_setfield(L, -2, "last_readtime");
+       lua_pushtimet(L, &peer->resettime);
+       lua_setfield(L, -2, "last_resettime");
+       lua_pushsockunion(L, peer->su_local);
+       lua_setfield(L, -2, "local_address");
+       lua_pushsockunion(L, peer->su_remote);
+       lua_setfield(L, -2, "remote_address");
+       lua_pushinteger(L, peer->cap);
+       lua_setfield(L, -2, "capabilities");
+       lua_pushinteger(L, peer->flags);
+       lua_setfield(L, -2, "flags");
+       lua_pushstring(L, peer->password ? peer->password : "");
+       lua_setfield(L, -2, "password");
+
+       /* Nested tables here */
+       lua_newtable(L);
+       {
+               lua_newtable(L);
+               {
+                       lua_pushinteger(L, peer->holdtime);
+                       lua_setfield(L, -2, "hold");
+                       lua_pushinteger(L, peer->keepalive);
+                       lua_setfield(L, -2, "keepalive");
+                       lua_pushinteger(L, peer->connect);
+                       lua_setfield(L, -2, "connect");
+                       lua_pushinteger(L, peer->routeadv);
+                       lua_setfield(L, -2, "route_advertisement");
+               }
+               lua_setfield(L, -2, "configured");
+
+               lua_newtable(L);
+               {
+                       lua_pushinteger(L, peer->v_holdtime);
+                       lua_setfield(L, -2, "hold");
+                       lua_pushinteger(L, peer->v_keepalive);
+                       lua_setfield(L, -2, "keepalive");
+                       lua_pushinteger(L, peer->v_connect);
+                       lua_setfield(L, -2, "connect");
+                       lua_pushinteger(L, peer->v_routeadv);
+                       lua_setfield(L, -2, "route_advertisement");
+               }
+               lua_setfield(L, -2, "negotiated");
+       }
+       lua_setfield(L, -2, "timers");
+
+       lua_newtable(L);
+       {
+               lua_pushinteger(L, atomic_load_explicit(&peer->open_in,
+                                                       memory_order_relaxed));
+               lua_setfield(L, -2, "open_in");
+               lua_pushinteger(L, atomic_load_explicit(&peer->open_out,
+                                                       memory_order_relaxed));
+               lua_setfield(L, -2, "open_out");
+               lua_pushinteger(L, atomic_load_explicit(&peer->update_in,
+                                                       memory_order_relaxed));
+               lua_setfield(L, -2, "update_in");
+               lua_pushinteger(L, atomic_load_explicit(&peer->update_out,
+                                                       memory_order_relaxed));
+               lua_setfield(L, -2, "update_out");
+               lua_pushinteger(L, atomic_load_explicit(&peer->update_time,
+                                                       memory_order_relaxed));
+               lua_setfield(L, -2, "update_time");
+               lua_pushinteger(L, atomic_load_explicit(&peer->keepalive_in,
+                                                       memory_order_relaxed));
+               lua_setfield(L, -2, "keepalive_in");
+               lua_pushinteger(L, atomic_load_explicit(&peer->keepalive_out,
+                                                       memory_order_relaxed));
+               lua_setfield(L, -2, "keepalive_out");
+               lua_pushinteger(L, atomic_load_explicit(&peer->notify_in,
+                                                       memory_order_relaxed));
+               lua_setfield(L, -2, "notify_in");
+               lua_pushinteger(L, atomic_load_explicit(&peer->notify_out,
+                                                       memory_order_relaxed));
+               lua_setfield(L, -2, "notify_out");
+               lua_pushinteger(L, atomic_load_explicit(&peer->refresh_in,
+                                                       memory_order_relaxed));
+               lua_setfield(L, -2, "refresh_in");
+               lua_pushinteger(L, atomic_load_explicit(&peer->refresh_out,
+                                                       memory_order_relaxed));
+               lua_setfield(L, -2, "refresh_out");
+               lua_pushinteger(L, atomic_load_explicit(&peer->dynamic_cap_in,
+                                                       memory_order_relaxed));
+               lua_setfield(L, -2, "dynamic_cap_in");
+               lua_pushinteger(L, atomic_load_explicit(&peer->dynamic_cap_out,
+                                                       memory_order_relaxed));
+               lua_setfield(L, -2, "dynamic_cap_out");
+               lua_pushinteger(L, peer->established);
+               lua_setfield(L, -2, "times_established");
+               lua_pushinteger(L, peer->dropped);
+               lua_setfield(L, -2, "times_dropped");
+       }
+       lua_setfield(L, -2, "stats");
+}
+
+static void lua_pushattr(lua_State *L, const struct attr *attr)
+{
+       lua_newtable(L);
+       lua_pushinteger(L, attr->med);
+       lua_setfield(L, -2, "metric");
+       lua_pushinteger(L, attr->nh_ifindex);
+       lua_setfield(L, -2, "ifindex");
+       lua_pushstring(L, attr->aspath->str);
+       lua_setfield(L, -2, "aspath");
+       lua_pushinteger(L, attr->local_pref);
+       lua_setfield(L, -2, "localpref");
+}
+
+static void *lua_toattr(lua_State *L, int idx)
+{
+       struct attr *attr = XCALLOC(MTYPE_TMP, sizeof(struct attr));
+
+       lua_getfield(L, -1, "metric");
+       attr->med = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, -1, "ifindex");
+       attr->nh_ifindex = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, -1, "aspath");
+       attr->aspath = aspath_str2aspath(lua_tostring(L, -1));
+       lua_pop(L, 1);
+       lua_getfield(L, -1, "localpref");
+       attr->local_pref = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+
+       return attr;
+}
+
+struct frrscript_codec frrscript_codecs_bgpd[] = {
+       {.typename = "peer",
+        .encoder = (encoder_func)lua_pushpeer,
+        .decoder = NULL},
+       {.typename = "attr",
+        .encoder = (encoder_func)lua_pushattr,
+        .decoder = lua_toattr},
+       {}};
+
+void bgp_script_init(void)
+{
+       frrscript_register_type_codecs(frrscript_codecs_bgpd);
+}
+
+#endif /* HAVE_SCRIPTING */
diff --git a/bgpd/bgp_script.h b/bgpd/bgp_script.h
new file mode 100644 (file)
index 0000000..6682c2e
--- /dev/null
@@ -0,0 +1,34 @@
+/* BGP scripting foo
+ * Copyright (C) 2020  NVIDIA Corporation
+ * Quentin Young
+ *
+ * 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 __BGP_SCRIPT__
+#define __BGP_SCRIPT__
+
+#include <zebra.h>
+
+#ifdef HAVE_SCRIPTING
+
+/*
+ * Initialize scripting stuff.
+ */
+void bgp_script_init(void);
+
+#endif /* HAVE_SCRIPTING */
+
+#endif /* __BGP_SCRIPT__ */
index 738d41ee6d7bb4d5f9f0e573f21c4d60fb9c730d..68b460149c2c4f95d0097d0958702089a7ed83fe 100644 (file)
@@ -104,6 +104,7 @@ struct bgp_node {
 #define BGP_NODE_SELECT_DEFER           (1 << 4)
 #define BGP_NODE_FIB_INSTALL_PENDING    (1 << 5)
 #define BGP_NODE_FIB_INSTALLED          (1 << 6)
+#define BGP_NODE_LABEL_REQUESTED        (1 << 7)
 
        struct bgp_addpath_node_data tx_addpath;
 
index 2788a8ea4ff48583938f819487ef1c12d5e4ba93..059e05ef71d06f3148755a5fe13b50925e9b498e 100644 (file)
@@ -1387,6 +1387,11 @@ static int updgrp_policy_update_walkcb(struct update_group *updgrp, void *arg)
        }
 
        UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
+               /* Avoid supressing duplicate routes later
+                * when processing in subgroup_announce_table().
+                */
+               SET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
+
                if (changed) {
                        if (bgp_debug_update(NULL, NULL, updgrp, 0))
                                zlog_debug(
index 9cad78c26d66866f7d0fb41ec57b2776cad36d5f..7261933dc98b0c6c4b21c27fce804a22e701ee3d 100644 (file)
@@ -252,19 +252,13 @@ struct update_subgroup {
        uint64_t id;
 
        uint16_t sflags;
+#define SUBGRP_STATUS_DEFAULT_ORIGINATE (1 << 0)
+#define SUBGRP_STATUS_FORCE_UPDATES (1 << 1)
 
-       /* Subgroup flags, see below  */
        uint16_t flags;
+#define SUBGRP_FLAG_NEEDS_REFRESH (1 << 0)
 };
 
-/*
- * We need to do an outbound refresh to get this subgroup into a
- * consistent state.
- */
-#define SUBGRP_FLAG_NEEDS_REFRESH         (1 << 0)
-
-#define SUBGRP_STATUS_DEFAULT_ORIGINATE   (1 << 0)
-
 /*
  * Add the given value to the specified counter on a subgroup and its
  * parent structures.
index da9e1f28aeff7de866dd578b07a51b0863f06232..30babb7b762b87a4c11f340d16918f21e6c04b27 100644 (file)
@@ -464,6 +464,7 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest,
        struct peer *adv_peer;
        struct peer_af *paf;
        struct bgp *bgp;
+       uint32_t attr_hash = attrhash_key_make(attr);
 
        peer = SUBGRP_PEER(subgrp);
        afi = SUBGRP_AFI(subgrp);
@@ -487,6 +488,26 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest,
                        return;
        }
 
+       /* Check if we are sending the same route. This is needed to
+        * avoid duplicate UPDATES. For instance, filtering communities
+        * at egress, neighbors will see duplicate UPDATES despite
+        * the route wasn't changed actually.
+        * Do not suppress BGP UPDATES for route-refresh.
+        */
+       if (CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES)
+           && !CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES)
+           && adj->attr_hash == attr_hash) {
+               if (BGP_DEBUG(update, UPDATE_OUT)) {
+                       char attr_str[BUFSIZ] = {0};
+
+                       bgp_dump_attr(attr, attr_str, sizeof(attr_str));
+
+                       zlog_debug("%s suppress UPDATE w/ attr: %s", peer->host,
+                                  attr_str);
+               }
+               return;
+       }
+
        if (adj->adv)
                bgp_advertise_clean_subgroup(subgrp, adj);
        adj->adv = bgp_advertise_new();
@@ -497,11 +518,9 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest,
        /* bgp_path_info adj_out reference */
        adv->pathi = bgp_path_info_lock(path);
 
-       if (attr)
-               adv->baa = bgp_advertise_intern(subgrp->hash, attr);
-       else
-               adv->baa = baa_new();
+       adv->baa = bgp_advertise_intern(subgrp->hash, attr);
        adv->adj = adj;
+       adj->attr_hash = attr_hash;
 
        /* Add new advertisement to advertisement attribute list. */
        bgp_advertise_add(adv->baa, adv);
index c3edb9e9a4a8cd5798db6e96a7ff85a85918ce6b..866bf8178a6c791613b78aa6daee1695236769ac 100644 (file)
@@ -575,7 +575,7 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
                }
 
                if (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg)) {
-                       if (peer->nexthop.v4.s_addr) {
+                       if (peer->nexthop.v4.s_addr != INADDR_ANY) {
                                ipv4_to_ipv4_mapped_ipv6(mod_v6nhg,
                                                         peer->nexthop.v4);
                        }
@@ -888,9 +888,12 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
                                        pkt_afi = afi_int2iana(afi);
                                        pkt_safi = safi_int2iana(safi);
                                        zlog_debug(
-                                               "u%" PRIu64 ":s%" PRIu64" send MP_REACH for afi/safi %d/%d",
+                                               "u%" PRIu64 ":s%" PRIu64
+                                               " send MP_REACH for afi/safi %s/%s",
                                                subgrp->update_group->id,
-                                               subgrp->id, pkt_afi, pkt_safi);
+                                               subgrp->id,
+                                               iana_afi2str(pkt_afi),
+                                               iana_safi2str(pkt_safi));
                                }
 
                                send_attr_printed = 1;
@@ -1046,9 +1049,12 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
                                if (bgp_debug_update(NULL, NULL,
                                                     subgrp->update_group, 0))
                                        zlog_debug(
-                                               "u%" PRIu64 ":s%" PRIu64" send MP_UNREACH for afi/safi %d/%d",
+                                               "u%" PRIu64 ":s%" PRIu64
+                                               " send MP_UNREACH for afi/safi %s/%s",
                                                subgrp->update_group->id,
-                                               subgrp->id, pkt_afi, pkt_safi);
+                                               subgrp->id,
+                                               iana_afi2str(pkt_afi),
+                                               iana_safi2str(pkt_safi));
                        }
 
                        bgp_packet_mpunreach_prefix(s, dest_p, afi, safi, prd,
index 30eb4a061016e55cdda01070b1b9977f853c9cdc..bd13b5cd5b1996322ab06db08f27c6b69618e640 100644 (file)
@@ -119,6 +119,10 @@ FRR_CFG_DEFAULT_BOOL(BGP_EBGP_REQUIRES_POLICY,
        { .val_bool = false, .match_version = "< 7.4", },
        { .val_bool = true },
 )
+FRR_CFG_DEFAULT_BOOL(BGP_SUPPRESS_DUPLICATES,
+       { .val_bool = false, .match_version = "< 7.6", },
+       { .val_bool = true },
+)
 
 DEFINE_HOOK(bgp_inst_config_write,
                (struct bgp *bgp, struct vty *vty),
@@ -209,34 +213,38 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi)
 
 static const char *get_afi_safi_vty_str(afi_t afi, safi_t safi)
 {
-       if (afi == AFI_IP && safi == SAFI_UNICAST)
-               return "IPv4 Unicast";
-       else if (afi == AFI_IP && safi == SAFI_MULTICAST)
-               return "IPv4 Multicast";
-       else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
-               return "IPv4 Labeled Unicast";
-       else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
-               return "IPv4 VPN";
-       else if (afi == AFI_IP && safi == SAFI_ENCAP)
-               return "IPv4 Encap";
-       else if (afi == AFI_IP && safi == SAFI_FLOWSPEC)
-               return "IPv4 Flowspec";
-       else if (afi == AFI_IP6 && safi == SAFI_UNICAST)
-               return "IPv6 Unicast";
-       else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
-               return "IPv6 Multicast";
-       else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
-               return "IPv6 Labeled Unicast";
-       else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
-               return "IPv6 VPN";
-       else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
-               return "IPv6 Encap";
-       else if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC)
-               return "IPv6 Flowspec";
-       else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
-               return "L2VPN EVPN";
-       else
-               return "Unknown";
+       if (afi == AFI_IP) {
+               if (safi == SAFI_UNICAST)
+                       return "IPv4 Unicast";
+               if (safi == SAFI_MULTICAST)
+                       return "IPv4 Multicast";
+               if (safi == SAFI_LABELED_UNICAST)
+                       return "IPv4 Labeled Unicast";
+               if (safi == SAFI_MPLS_VPN)
+                       return "IPv4 VPN";
+               if (safi == SAFI_ENCAP)
+                       return "IPv4 Encap";
+               if (safi == SAFI_FLOWSPEC)
+                       return "IPv4 Flowspec";
+       } else if (afi == AFI_IP6) {
+               if (safi == SAFI_UNICAST)
+                       return "IPv6 Unicast";
+               if (safi == SAFI_MULTICAST)
+                       return "IPv6 Multicast";
+               if (safi == SAFI_LABELED_UNICAST)
+                       return "IPv6 Labeled Unicast";
+               if (safi == SAFI_MPLS_VPN)
+                       return "IPv6 VPN";
+               if (safi == SAFI_ENCAP)
+                       return "IPv6 Encap";
+               if (safi == SAFI_FLOWSPEC)
+                       return "IPv6 Flowspec";
+       } else if (afi == AFI_L2VPN) {
+               if (safi == SAFI_EVPN)
+                       return "L2VPN EVPN";
+       }
+
+       return "Unknown";
 }
 
 /*
@@ -247,34 +255,38 @@ static const char *get_afi_safi_vty_str(afi_t afi, safi_t safi)
  */
 static const char *get_afi_safi_json_str(afi_t afi, safi_t safi)
 {
-       if (afi == AFI_IP && safi == SAFI_UNICAST)
-               return "ipv4Unicast";
-       else if (afi == AFI_IP && safi == SAFI_MULTICAST)
-               return "ipv4Multicast";
-       else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
-               return "ipv4LabeledUnicast";
-       else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
-               return "ipv4Vpn";
-       else if (afi == AFI_IP && safi == SAFI_ENCAP)
-               return "ipv4Encap";
-       else if (afi == AFI_IP && safi == SAFI_FLOWSPEC)
-               return "ipv4Flowspec";
-       else if (afi == AFI_IP6 && safi == SAFI_UNICAST)
-               return "ipv6Unicast";
-       else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
-               return "ipv6Multicast";
-       else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
-               return "ipv6LabeledUnicast";
-       else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
-               return "ipv6Vpn";
-       else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
-               return "ipv6Encap";
-       else if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC)
-               return "ipv6Flowspec";
-       else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
-               return "l2VpnEvpn";
-       else
-               return "Unknown";
+       if (afi == AFI_IP) {
+               if (safi == SAFI_UNICAST)
+                       return "ipv4Unicast";
+               if (safi == SAFI_MULTICAST)
+                       return "ipv4Multicast";
+               if (safi == SAFI_LABELED_UNICAST)
+                       return "ipv4LabeledUnicast";
+               if (safi == SAFI_MPLS_VPN)
+                       return "ipv4Vpn";
+               if (safi == SAFI_ENCAP)
+                       return "ipv4Encap";
+               if (safi == SAFI_FLOWSPEC)
+                       return "ipv4Flowspec";
+       } else if (afi == AFI_IP6) {
+               if (safi == SAFI_UNICAST)
+                       return "ipv6Unicast";
+               if (safi == SAFI_MULTICAST)
+                       return "ipv6Multicast";
+               if (safi == SAFI_LABELED_UNICAST)
+                       return "ipv6LabeledUnicast";
+               if (safi == SAFI_MPLS_VPN)
+                       return "ipv6Vpn";
+               if (safi == SAFI_ENCAP)
+                       return "ipv6Encap";
+               if (safi == SAFI_FLOWSPEC)
+                       return "ipv6Flowspec";
+       } else if (afi == AFI_L2VPN) {
+               if (safi == SAFI_EVPN)
+                       return "l2VpnEvpn";
+       }
+
+       return "Unknown";
 }
 
 /* return string maps to afi-safi specific container names
@@ -282,30 +294,34 @@ static const char *get_afi_safi_json_str(afi_t afi, safi_t safi)
  */
 const char *bgp_afi_safi_get_container_str(afi_t afi, safi_t safi)
 {
-       if (afi == AFI_IP && safi == SAFI_UNICAST)
-               return "ipv4-unicast";
-       else if (afi == AFI_IP && safi == SAFI_MULTICAST)
-               return "ipv4-multicast";
-       else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
-               return "ipv4-labeled-unicast";
-       else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
-               return "l3vpn-ipv4-unicast";
-       else if (afi == AFI_IP && safi == SAFI_FLOWSPEC)
-               return "ipv4-flowspec";
-       else if (afi == AFI_IP6 && safi == SAFI_UNICAST)
-               return "ipv6-unicast";
-       else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
-               return "ipv6-multicast";
-       else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
-               return "ipv6-labeled-unicast";
-       else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
-               return "l3vpn-ipv6-unicast";
-       else if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC)
-               return "ipv6-flowspec";
-       else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
-               return "l2vpn-evpn";
-       else
-               return "Unknown";
+       if (afi == AFI_IP) {
+               if (safi == SAFI_UNICAST)
+                       return "ipv4-unicast";
+               if (safi == SAFI_MULTICAST)
+                       return "ipv4-multicast";
+               if (safi == SAFI_LABELED_UNICAST)
+                       return "ipv4-labeled-unicast";
+               if (safi == SAFI_MPLS_VPN)
+                       return "l3vpn-ipv4-unicast";
+               if (safi == SAFI_FLOWSPEC)
+                       return "ipv4-flowspec";
+       } else if (afi == AFI_IP6) {
+               if (safi == SAFI_UNICAST)
+                       return "ipv6-unicast";
+               if (safi == SAFI_MULTICAST)
+                       return "ipv6-multicast";
+               if (safi == SAFI_LABELED_UNICAST)
+                       return "ipv6-labeled-unicast";
+               if (safi == SAFI_MPLS_VPN)
+                       return "l3vpn-ipv6-unicast";
+               if (safi == SAFI_FLOWSPEC)
+                       return "ipv6-flowspec";
+       } else if (afi == AFI_L2VPN) {
+               if (safi == SAFI_EVPN)
+                       return "l2vpn-evpn";
+       }
+
+       return "Unknown";
 }
 
 /* Utility function to get address family from current node.  */
@@ -461,7 +477,7 @@ int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
 
        if (ret == BGP_CREATED) {
                bgp_timers_set(*bgp, DFLT_BGP_KEEPALIVE, DFLT_BGP_HOLDTIME,
-                              DFLT_BGP_CONNECT_RETRY);
+                              DFLT_BGP_CONNECT_RETRY, BGP_DEFAULT_DELAYOPEN);
 
                if (DFLT_BGP_IMPORT_CHECK)
                        SET_FLAG((*bgp)->flags, BGP_FLAG_IMPORT_CHECK);
@@ -475,6 +491,8 @@ int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
                        SET_FLAG((*bgp)->flags, BGP_FLAG_DETERMINISTIC_MED);
                if (DFLT_BGP_EBGP_REQUIRES_POLICY)
                        SET_FLAG((*bgp)->flags, BGP_FLAG_EBGP_REQUIRES_POLICY);
+               if (DFLT_BGP_SUPPRESS_DUPLICATES)
+                       SET_FLAG((*bgp)->flags, BGP_FLAG_SUPPRESS_DUPLICATES);
 
                ret = BGP_SUCCESS;
        }
@@ -864,6 +882,7 @@ static int bgp_peer_clear(struct peer *peer, afi_t afi, safi_t safi,
                          struct listnode **nnode, enum bgp_clear_type stype)
 {
        int ret = 0;
+       struct peer_af *paf;
 
        /* if afi/.safi not specified, spin thru all of them */
        if ((afi == AFI_UNSPEC) && (safi == SAFI_UNSPEC)) {
@@ -871,6 +890,11 @@ static int bgp_peer_clear(struct peer *peer, afi_t afi, safi_t safi,
                safi_t tmp_safi;
 
                FOREACH_AFI_SAFI (tmp_afi, tmp_safi) {
+                       paf = peer_af_find(peer, tmp_afi, tmp_safi);
+                       if (paf && paf->subgroup)
+                               SET_FLAG(paf->subgroup->sflags,
+                                        SUBGRP_STATUS_FORCE_UPDATES);
+
                        if (!peer->afc[tmp_afi][tmp_safi])
                                continue;
 
@@ -889,6 +913,11 @@ static int bgp_peer_clear(struct peer *peer, afi_t afi, safi_t safi,
                        if (!peer->afc[afi][tmp_safi])
                                continue;
 
+                       paf = peer_af_find(peer, afi, tmp_safi);
+                       if (paf && paf->subgroup)
+                               SET_FLAG(paf->subgroup->sflags,
+                                        SUBGRP_STATUS_FORCE_UPDATES);
+
                        if (stype == BGP_CLEAR_SOFT_NONE)
                                ret = peer_clear(peer, nnode);
                        else
@@ -900,6 +929,11 @@ static int bgp_peer_clear(struct peer *peer, afi_t afi, safi_t safi,
                if (!peer->afc[afi][safi])
                        return 1;
 
+               paf = peer_af_find(peer, afi, safi);
+               if (paf && paf->subgroup)
+                       SET_FLAG(paf->subgroup->sflags,
+                                SUBGRP_STATUS_FORCE_UPDATES);
+
                if (stype == BGP_CLEAR_SOFT_NONE)
                        ret = peer_clear(peer, nnode);
                else
@@ -1514,6 +1548,18 @@ void cli_show_router_bgp_router_id(struct vty *vty, struct lyd_node *dnode,
        vty_out(vty, " bgp router-id %s\n", yang_dnode_get_string(dnode, NULL));
 }
 
+DEFPY (bgp_global_suppress_fib_pending,
+       bgp_global_suppress_fib_pending_cmd,
+       "[no] bgp suppress-fib-pending",
+       NO_STR
+       BGP_STR
+       "Advertise only routes that are programmed in kernel to peers globally\n")
+{
+       bm_wait_for_fib_set(!no);
+
+       return CMD_SUCCESS;
+}
+
 DEFPY (bgp_suppress_fib_pending,
        bgp_suppress_fib_pending_cmd,
        "[no] bgp suppress-fib-pending",
@@ -1596,6 +1642,22 @@ DEFPY (no_bgp_norib,
        return CMD_SUCCESS;
 }
 
+DEFPY (no_bgp_send_extra_data,
+       no_bgp_send_extra_data_cmd,
+       "[no] bgp send-extra-data zebra",
+       NO_STR
+       BGP_STR
+       "Extra data to Zebra for display/use\n"
+       "To zebra\n")
+{
+       if (no)
+               UNSET_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA);
+       else
+               SET_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA);
+
+       return CMD_SUCCESS;
+}
+
 DEFUN_YANG(bgp_confederation_identifier,
           bgp_confederation_identifier_cmd,
           "bgp confederation identifier (1-4294967295)",
@@ -2352,12 +2414,12 @@ ALIAS_HIDDEN(no_bgp_maxpaths_ibgp, no_bgp_maxpaths_ibgp_hidden_cmd,
 static void bgp_config_write_maxpaths(struct vty *vty, struct bgp *bgp,
                                      afi_t afi, safi_t safi)
 {
-       if (bgp->maxpaths[afi][safi].maxpaths_ebgp != MULTIPATH_NUM) {
+       if (bgp->maxpaths[afi][safi].maxpaths_ebgp != multipath_num) {
                vty_out(vty, "  maximum-paths %d\n",
                        bgp->maxpaths[afi][safi].maxpaths_ebgp);
        }
 
-       if (bgp->maxpaths[afi][safi].maxpaths_ibgp != MULTIPATH_NUM) {
+       if (bgp->maxpaths[afi][safi].maxpaths_ibgp != multipath_num) {
                vty_out(vty, "  maximum-paths ibgp %d",
                        bgp->maxpaths[afi][safi].maxpaths_ibgp);
                if (CHECK_FLAG(bgp->maxpaths[afi][safi].ibgp_flags,
@@ -2515,6 +2577,37 @@ DEFUN_YANG(no_bgp_always_compare_med,
        return nb_cli_apply_changes(vty, NULL);
 }
 
+DEFUN_YANG(bgp_suppress_duplicates,
+          bgp_suppress_duplicates_cmd,
+          "bgp suppress-duplicates",
+          "BGP specific commands\n"
+          "Suppress duplicate updates if the route actually not changed\n")
+{
+       nb_cli_enqueue_change(vty, "./global/suppress-duplicates",
+                             NB_OP_MODIFY, "true");
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN_YANG(no_bgp_suppress_duplicates,
+          no_bgp_suppress_duplicates_cmd,
+          "no bgp suppress-duplicates",
+          NO_STR
+          "BGP specific commands\n"
+          "Suppress duplicate updates if the route actually not changed\n")
+{
+       nb_cli_enqueue_change(vty, "./global/suppress-duplicates",
+                             NB_OP_MODIFY, "false");
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_router_bgp_suppress_duplicates(struct vty *vty,
+                                             struct lyd_node *dnode,
+                                             bool show_defaults)
+{
+       if (yang_dnode_get_bool(dnode, NULL) != SAVE_BGP_SUPPRESS_DUPLICATES)
+               vty_out(vty, " bgp suppress-duplicates\n");
+}
+
 DEFUN_YANG(bgp_ebgp_requires_policy,
           bgp_ebgp_requires_policy_cmd,
           "bgp ebgp-requires-policy",
@@ -4263,7 +4356,6 @@ int peer_conf_interface_create(struct bgp *bgp, const char *conf_if, afi_t afi,
        struct peer *peer;
        struct peer_group *group;
        int ret = 0;
-       union sockunion su;
 
        group = peer_group_lookup(bgp, conf_if);
 
@@ -4338,7 +4430,7 @@ int peer_conf_interface_create(struct bgp *bgp, const char *conf_if, afi_t afi,
                        return -1;
                }
 
-               ret = peer_group_bind(bgp, &su, peer, group, &as);
+               ret = peer_group_bind(bgp, NULL, peer, group, &as);
        }
 
        return bgp_nb_errmsg_return(errmsg, errmsg_len, ret);
@@ -4860,27 +4952,63 @@ ALIAS_HIDDEN(no_neighbor_activate, no_neighbor_activate_hidden_cmd,
             NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
             "Enable the Address Family for this Neighbor\n")
 
-DEFUN_YANG (neighbor_set_peer_group,
-           neighbor_set_peer_group_cmd,
-           "neighbor <A.B.C.D|X:X::X:X|WORD> peer-group PGNAME",
-           NEIGHBOR_STR
-           NEIGHBOR_ADDR_STR2
-           "Member of the peer-group\n"
-           "Peer-group name\n")
+DEFUN (neighbor_set_peer_group,
+       neighbor_set_peer_group_cmd,
+       "neighbor <A.B.C.D|X:X::X:X|WORD> peer-group PGNAME",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Member of the peer-group\n"
+       "Peer-group name\n")
 {
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
        int idx_peer = 1;
        int idx_word = 3;
-       char base_xpath[XPATH_MAXLEN];
+       int ret;
+       as_t as;
+       union sockunion su;
+       struct peer *peer;
+       struct peer_group *group;
 
-       if (peer_and_group_lookup_nb(vty, argv[idx_peer]->arg, base_xpath,
-                                    sizeof(base_xpath), NULL)
-           < 0)
+       ret = str2sockunion(argv[idx_peer]->arg, &su);
+       if (ret < 0) {
+               peer = peer_lookup_by_conf_if(bgp, argv[idx_peer]->arg);
+               if (!peer) {
+                       vty_out(vty, "%% Malformed address or name: %s\n",
+                               argv[idx_peer]->arg);
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+       } else {
+               if (peer_address_self_check(bgp, &su)) {
+                       vty_out(vty,
+                               "%% Can not configure the local system as neighbor\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+
+               /* Disallow for dynamic neighbor. */
+               peer = peer_lookup(bgp, &su);
+               if (peer && peer_dynamic_neighbor(peer)) {
+                       vty_out(vty,
+                               "%% Operation not allowed on a dynamic neighbor\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+       }
+
+       group = peer_group_lookup(bgp, argv[idx_word]->arg);
+       if (!group) {
+               vty_out(vty, "%% Configure the peer-group first\n");
                return CMD_WARNING_CONFIG_FAILED;
+       }
 
-       nb_cli_enqueue_change(vty, "./peer-group", NB_OP_MODIFY,
-                             argv[idx_word]->arg);
+       ret = peer_group_bind(bgp, &su, peer, group, &as);
 
-       return nb_cli_apply_changes(vty, base_xpath);
+       if (ret == BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT) {
+               vty_out(vty,
+                       "%% Peer with AS %u cannot be in this peer-group, members must be all internal or all external\n",
+                       as);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return bgp_vty_return(vty, ret);
 }
 
 ALIAS_HIDDEN(neighbor_set_peer_group, neighbor_set_peer_group_hidden_cmd,
@@ -5436,7 +5564,6 @@ DEFUN_YANG (neighbor_nexthop_self,
        afi_t afi = bgp_node_afi(vty);
        safi_t safi = bgp_node_safi(vty);
 
-
        snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
                 yang_afi_safi_value2identity(afi, safi));
 
@@ -5475,7 +5602,6 @@ DEFUN_YANG(neighbor_nexthop_self_force,
        afi_t afi = bgp_node_afi(vty);
        safi_t safi = bgp_node_safi(vty);
 
-
        snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
                 yang_afi_safi_value2identity(afi, safi));
 
@@ -5560,7 +5686,6 @@ DEFUN_YANG (no_neighbor_nexthop_self_force,
        afi_t afi = bgp_node_afi(vty);
        safi_t safi = bgp_node_safi(vty);
 
-
        snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
                 yang_afi_safi_value2identity(afi, safi));
 
@@ -5718,7 +5843,6 @@ DEFUN_YANG (neighbor_remove_private_as_all,
        afi_t afi = bgp_node_afi(vty);
        safi_t safi = bgp_node_safi(vty);
 
-
        snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
                 yang_afi_safi_value2identity(afi, safi));
 
@@ -5758,7 +5882,6 @@ DEFUN_YANG (neighbor_remove_private_as_replace_as,
        afi_t afi = bgp_node_afi(vty);
        safi_t safi = bgp_node_safi(vty);
 
-
        snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
                 yang_afi_safi_value2identity(afi, safi));
 
@@ -5799,7 +5922,6 @@ DEFUN_YANG (neighbor_remove_private_as_all_replace_as,
        afi_t afi = bgp_node_afi(vty);
        safi_t safi = bgp_node_safi(vty);
 
-
        snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
                 yang_afi_safi_value2identity(afi, safi));
 
@@ -5880,7 +6002,6 @@ DEFUN_YANG (no_neighbor_remove_private_as_all,
        afi_t afi = bgp_node_afi(vty);
        safi_t safi = bgp_node_safi(vty);
 
-
        snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
                 yang_afi_safi_value2identity(afi, safi));
 
@@ -5921,7 +6042,6 @@ DEFUN_YANG (no_neighbor_remove_private_as_replace_as,
        afi_t afi = bgp_node_afi(vty);
        safi_t safi = bgp_node_safi(vty);
 
-
        snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
                 yang_afi_safi_value2identity(afi, safi));
 
@@ -5963,7 +6083,6 @@ DEFUN_YANG (no_neighbor_remove_private_as_all_replace_as,
        afi_t afi = bgp_node_afi(vty);
        safi_t safi = bgp_node_safi(vty);
 
-
        snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
                 yang_afi_safi_value2identity(afi, safi));
 
@@ -6253,7 +6372,6 @@ DEFUN_YANG (neighbor_soft_reconfiguration,
        afi_t afi = bgp_node_afi(vty);
        safi_t safi = bgp_node_safi(vty);
 
-
        snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
                 yang_afi_safi_value2identity(afi, safi));
 
@@ -7374,6 +7492,54 @@ DEFUN_YANG (no_neighbor_timers_connect,
        return nb_cli_apply_changes(vty, base_xpath);
 }
 
+DEFPY (neighbor_timers_delayopen,
+       neighbor_timers_delayopen_cmd,
+       "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor timers delayopen (1-240)$interval",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP per neighbor timers\n"
+       "RFC 4271 DelayOpenTimer\n"
+       "DelayOpenTime timer interval\n")
+{
+       struct peer *peer;
+
+       peer = peer_and_group_lookup_vty(vty, neighbor);
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       if (!interval) {
+               if (peer_timers_delayopen_unset(peer))
+                       return CMD_WARNING_CONFIG_FAILED;
+       } else {
+               if (peer_timers_delayopen_set(peer, interval))
+                       return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFPY (no_neighbor_timers_delayopen,
+       no_neighbor_timers_delayopen_cmd,
+       "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor timers delayopen [(0-65535)]",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "BGP per neighbor timers\n"
+       "RFC 4271 DelayOpenTimer\n"
+       "DelayOpenTime timer interval\n")
+{
+       struct peer *peer;
+
+       peer = peer_and_group_lookup_vty(vty, neighbor);
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       if (peer_timers_delayopen_unset(peer))
+               return CMD_WARNING_CONFIG_FAILED;
+
+       return CMD_SUCCESS;
+}
+
 DEFUN_YANG (neighbor_advertise_interval,
            neighbor_advertise_interval_cmd,
            "neighbor <A.B.C.D|X:X::X:X|WORD> advertisement-interval (0-600)",
@@ -7592,69 +7758,44 @@ ALIAS_HIDDEN(
        "Filter outgoing updates\n")
 
 /* Set prefix list to the peer. */
-static int peer_prefix_list_set_vty(struct vty *vty, const char *ip_str,
-                                   afi_t afi, safi_t safi,
-                                   const char *name_str,
-                                   const char *direct_str)
-{
-       int ret;
-       int direct = FILTER_IN;
-       struct peer *peer;
-
-       peer = peer_and_group_lookup_vty(vty, ip_str);
-       if (!peer)
-               return CMD_WARNING_CONFIG_FAILED;
-
-       /* Check filter direction. */
-       if (strncmp(direct_str, "i", 1) == 0)
-               direct = FILTER_IN;
-       else if (strncmp(direct_str, "o", 1) == 0)
-               direct = FILTER_OUT;
-
-       ret = peer_prefix_list_set(peer, afi, safi, direct, name_str);
-
-       return bgp_vty_return(vty, ret);
-}
-
-static int peer_prefix_list_unset_vty(struct vty *vty, const char *ip_str,
-                                     afi_t afi, safi_t safi,
-                                     const char *direct_str)
+DEFPY_YANG(
+       neighbor_prefix_list, neighbor_prefix_list_cmd,
+       "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor_str prefix-list WORD$prefix_str <in|out>$direction",
+       NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
+       "Filter updates to/from this neighbor\n"
+       "Name of a prefix list\n"
+       "Filter incoming updates\n"
+       "Filter outgoing updates\n")
 {
-       int ret;
-       struct peer *peer;
-       int direct = FILTER_IN;
+       char base_xpath[XPATH_MAXLEN];
+       char af_xpath[XPATH_MAXLEN];
+       char plist_xpath[XPATH_MAXLEN];
+       afi_t afi = bgp_node_afi(vty);
+       safi_t safi = bgp_node_safi(vty);
 
-       peer = peer_and_group_lookup_vty(vty, ip_str);
-       if (!peer)
+       snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
+                yang_afi_safi_value2identity(afi, safi));
+       if (peer_and_group_lookup_nb(vty, neighbor_str, base_xpath,
+                                    sizeof(base_xpath), af_xpath)
+           < 0)
                return CMD_WARNING_CONFIG_FAILED;
 
-       /* Check filter direction. */
-       if (strncmp(direct_str, "i", 1) == 0)
-               direct = FILTER_IN;
-       else if (strncmp(direct_str, "o", 1) == 0)
-               direct = FILTER_OUT;
-
-       ret = peer_prefix_list_unset(peer, afi, safi, direct);
+       if (strmatch(direction, "in"))
+               snprintf(plist_xpath, sizeof(plist_xpath),
+                        "./%s/filter-config/plist-import",
+                        bgp_afi_safi_get_container_str(afi, safi));
+       else if (strmatch(direction, "out"))
+               snprintf(plist_xpath, sizeof(plist_xpath),
+                        "./%s/filter-config/plist-export",
+                        bgp_afi_safi_get_container_str(afi, safi));
 
-       return bgp_vty_return(vty, ret);
-}
+       if (!no)
+               nb_cli_enqueue_change(vty, plist_xpath, NB_OP_MODIFY,
+                                     prefix_str);
+       else
+               nb_cli_enqueue_change(vty, plist_xpath, NB_OP_DESTROY, NULL);
 
-DEFUN (neighbor_prefix_list,
-       neighbor_prefix_list_cmd,
-       "neighbor <A.B.C.D|X:X::X:X|WORD> prefix-list WORD <in|out>",
-       NEIGHBOR_STR
-       NEIGHBOR_ADDR_STR2
-       "Filter updates to/from this neighbor\n"
-       "Name of a prefix list\n"
-       "Filter incoming updates\n"
-       "Filter outgoing updates\n")
-{
-       int idx_peer = 1;
-       int idx_word = 3;
-       int idx_in_out = 4;
-       return peer_prefix_list_set_vty(
-               vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty),
-               argv[idx_word]->arg, argv[idx_in_out]->arg);
+       return nb_cli_apply_changes(vty, base_xpath);
 }
 
 ALIAS_HIDDEN(neighbor_prefix_list, neighbor_prefix_list_hidden_cmd,
@@ -7665,32 +7806,6 @@ ALIAS_HIDDEN(neighbor_prefix_list, neighbor_prefix_list_hidden_cmd,
             "Filter incoming updates\n"
             "Filter outgoing updates\n")
 
-DEFUN (no_neighbor_prefix_list,
-       no_neighbor_prefix_list_cmd,
-       "no neighbor <A.B.C.D|X:X::X:X|WORD> prefix-list WORD <in|out>",
-       NO_STR
-       NEIGHBOR_STR
-       NEIGHBOR_ADDR_STR2
-       "Filter updates to/from this neighbor\n"
-       "Name of a prefix list\n"
-       "Filter incoming updates\n"
-       "Filter outgoing updates\n")
-{
-       int idx_peer = 2;
-       int idx_in_out = 5;
-       return peer_prefix_list_unset_vty(vty, argv[idx_peer]->arg,
-                                         bgp_node_afi(vty), bgp_node_safi(vty),
-                                         argv[idx_in_out]->arg);
-}
-
-ALIAS_HIDDEN(no_neighbor_prefix_list, no_neighbor_prefix_list_hidden_cmd,
-            "no neighbor <A.B.C.D|X:X::X:X|WORD> prefix-list WORD <in|out>",
-            NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
-            "Filter updates to/from this neighbor\n"
-            "Name of a prefix list\n"
-            "Filter incoming updates\n"
-            "Filter outgoing updates\n")
-
 static int peer_aslist_set_vty(struct vty *vty, const char *ip_str, afi_t afi,
                               safi_t safi, const char *name_str,
                               const char *direct_str)
@@ -7851,70 +7966,52 @@ ALIAS_HIDDEN(neighbor_advertise_map, neighbor_advertise_map_hidden_cmd,
             "Name of the exist or non exist map\n")
 
 /* Set route-map to the peer. */
-static int peer_route_map_set_vty(struct vty *vty, const char *ip_str,
-                                 afi_t afi, safi_t safi, const char *name_str,
-                                 const char *direct_str)
-{
-       int ret;
-       struct peer *peer;
-       int direct = RMAP_IN;
-       struct route_map *route_map;
-
-       peer = peer_and_group_lookup_vty(vty, ip_str);
-       if (!peer)
-               return CMD_WARNING_CONFIG_FAILED;
-
-       /* Check filter direction. */
-       if (strncmp(direct_str, "in", 2) == 0)
-               direct = RMAP_IN;
-       else if (strncmp(direct_str, "o", 1) == 0)
-               direct = RMAP_OUT;
-
-       route_map = route_map_lookup_warn_noexist(vty, name_str);
-       ret = peer_route_map_set(peer, afi, safi, direct, name_str, route_map);
-
-       return bgp_vty_return(vty, ret);
-}
-
-static int peer_route_map_unset_vty(struct vty *vty, const char *ip_str,
-                                   afi_t afi, safi_t safi,
-                                   const char *direct_str)
+DEFPY_YANG(
+       neighbor_route_map, neighbor_route_map_cmd,
+       "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor_str route-map WORD$rmap_str  <in|out>$direction",
+       NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
+       "Apply route map to neighbor\n"
+       "Name of route map\n"
+       "Apply map to incoming routes\n"
+       "Apply map to outbound routes\n")
 {
-       int ret;
-       struct peer *peer;
-       int direct = RMAP_IN;
+       char base_xpath[XPATH_MAXLEN];
+       char af_xpath[XPATH_MAXLEN];
+       char rmap_xpath[XPATH_MAXLEN];
+       afi_t afi = bgp_node_afi(vty);
+       safi_t safi = bgp_node_safi(vty);
 
-       peer = peer_and_group_lookup_vty(vty, ip_str);
-       if (!peer)
+       snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
+                yang_afi_safi_value2identity(afi, safi));
+       if (peer_and_group_lookup_nb(vty, neighbor_str, base_xpath,
+                                    sizeof(base_xpath), af_xpath)
+           < 0)
                return CMD_WARNING_CONFIG_FAILED;
 
-       /* Check filter direction. */
-       if (strncmp(direct_str, "in", 2) == 0)
-               direct = RMAP_IN;
-       else if (strncmp(direct_str, "o", 1) == 0)
-               direct = RMAP_OUT;
-
-       ret = peer_route_map_unset(peer, afi, safi, direct);
+       if (strmatch(direction, "in"))
+               snprintf(rmap_xpath, sizeof(rmap_xpath),
+                        "./%s/filter-config/rmap-import",
+                        bgp_afi_safi_get_container_str(afi, safi));
+       else if (strmatch(direction, "out"))
+               snprintf(rmap_xpath, sizeof(rmap_xpath),
+                        "./%s/filter-config/rmap-export",
+                        bgp_afi_safi_get_container_str(afi, safi));
 
-       return bgp_vty_return(vty, ret);
-}
+       if (!no) {
+               if (!yang_dnode_exists(
+                           vty->candidate_config->dnode,
+                           "/frr-route-map:lib/route-map[name='%s']",
+                           rmap_str)) {
+                       if (vty_shell_serv(vty))
+                               vty_out(vty,
+                                       "The route-map '%s' does not exist.\n",
+                                       rmap_str);
+               }
+               nb_cli_enqueue_change(vty, rmap_xpath, NB_OP_MODIFY, rmap_str);
+       } else
+               nb_cli_enqueue_change(vty, rmap_xpath, NB_OP_DESTROY, NULL);
 
-DEFUN (neighbor_route_map,
-       neighbor_route_map_cmd,
-       "neighbor <A.B.C.D|X:X::X:X|WORD> route-map WORD <in|out>",
-       NEIGHBOR_STR
-       NEIGHBOR_ADDR_STR2
-       "Apply route map to neighbor\n"
-       "Name of route map\n"
-       "Apply map to incoming routes\n"
-       "Apply map to outbound routes\n")
-{
-       int idx_peer = 1;
-       int idx_word = 3;
-       int idx_in_out = 4;
-       return peer_route_map_set_vty(
-               vty, argv[idx_peer]->arg, bgp_node_afi(vty), bgp_node_safi(vty),
-               argv[idx_word]->arg, argv[idx_in_out]->arg);
+       return nb_cli_apply_changes(vty, base_xpath);
 }
 
 ALIAS_HIDDEN(neighbor_route_map, neighbor_route_map_hidden_cmd,
@@ -7925,25 +8022,7 @@ ALIAS_HIDDEN(neighbor_route_map, neighbor_route_map_hidden_cmd,
             "Apply map to incoming routes\n"
             "Apply map to outbound routes\n")
 
-DEFUN (no_neighbor_route_map,
-       no_neighbor_route_map_cmd,
-       "no neighbor <A.B.C.D|X:X::X:X|WORD> route-map WORD <in|out>",
-       NO_STR
-       NEIGHBOR_STR
-       NEIGHBOR_ADDR_STR2
-       "Apply route map to neighbor\n"
-       "Name of route map\n"
-       "Apply map to incoming routes\n"
-       "Apply map to outbound routes\n")
-{
-       int idx_peer = 2;
-       int idx_in_out = 5;
-       return peer_route_map_unset_vty(vty, argv[idx_peer]->arg,
-                                       bgp_node_afi(vty), bgp_node_safi(vty),
-                                       argv[idx_in_out]->arg);
-}
-
-ALIAS_HIDDEN(no_neighbor_route_map, no_neighbor_route_map_hidden_cmd,
+ALIAS_HIDDEN(neighbor_route_map, no_neighbor_route_map_hidden_cmd,
             "no neighbor <A.B.C.D|X:X::X:X|WORD> route-map WORD <in|out>",
             NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
             "Apply route map to neighbor\n"
@@ -8756,6 +8835,93 @@ DEFPY(
        return CMD_SUCCESS;
 }
 
+DEFPY(neighbor_damp,
+      neighbor_damp_cmd,
+      "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor dampening [(1-45)$half [(1-20000)$reuse (1-20000)$suppress (1-255)$max]]",
+      NEIGHBOR_STR
+      NEIGHBOR_ADDR_STR2
+      "Enable neighbor route-flap dampening\n"
+      "Half-life time for the penalty\n"
+      "Value to start reusing a route\n"
+      "Value to start suppressing a route\n"
+      "Maximum duration to suppress a stable route\n")
+{
+       struct peer *peer = peer_and_group_lookup_vty(vty, neighbor);
+
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
+       if (!half)
+               half = DEFAULT_HALF_LIFE;
+       if (!reuse) {
+               reuse = DEFAULT_REUSE;
+               suppress = DEFAULT_SUPPRESS;
+               max = half * 4;
+       }
+       if (suppress < reuse) {
+               vty_out(vty,
+                       "Suppress value cannot be less than reuse value\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+       bgp_peer_damp_enable(peer, bgp_node_afi(vty), bgp_node_safi(vty),
+                            half * 60, reuse, suppress, max * 60);
+       return CMD_SUCCESS;
+}
+
+DEFPY(no_neighbor_damp,
+      no_neighbor_damp_cmd,
+      "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor dampening [HALF [REUSE SUPPRESS MAX]]",
+      NO_STR
+      NEIGHBOR_STR
+      NEIGHBOR_ADDR_STR2
+      "Enable neighbor route-flap dampening\n"
+      "Half-life time for the penalty\n"
+      "Value to start reusing a route\n"
+      "Value to start suppressing a route\n"
+      "Maximum duration to suppress a stable route\n")
+{
+       struct peer *peer = peer_and_group_lookup_vty(vty, neighbor);
+
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
+       bgp_peer_damp_disable(peer, bgp_node_afi(vty), bgp_node_safi(vty));
+       return CMD_SUCCESS;
+}
+
+DEFPY (show_ip_bgp_neighbor_damp_param,
+       show_ip_bgp_neighbor_damp_param_cmd,
+       "show [ip] bgp [<ipv4|ipv6> [unicast]] neighbors <A.B.C.D|X:X::X:X|WORD>$neighbor dampening parameters [json]$json",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       BGP_AFI_HELP_STR
+       "Address Family modifier\n"
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Neighbor route-flap dampening information\n"
+       "Display detail of configured dampening parameters\n"
+       JSON_STR)
+{
+       bool use_json = false;
+       int idx = 0;
+       afi_t afi = AFI_IP;
+       safi_t safi = SAFI_UNICAST;
+       struct peer *peer;
+
+       if (argv_find(argv, argc, "ip", &idx))
+               afi = AFI_IP;
+       if (argv_find(argv, argc, "ipv4", &idx))
+               afi = AFI_IP;
+       if (argv_find(argv, argc, "ipv6", &idx))
+               afi = AFI_IP6;
+       peer = peer_and_group_lookup_vty(vty, neighbor);
+       if (!peer)
+               return CMD_WARNING;
+       if (json)
+               use_json = true;
+       bgp_show_peer_dampening_parameters(vty, peer, afi, safi, use_json);
+       return CMD_SUCCESS;
+}
+
 static int set_ecom_list(struct vty *vty, int argc, struct cmd_token **argv,
                         struct ecommunity **list, bool is_rt6)
 {
@@ -10743,7 +10909,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                        vty_out(vty, "EstdCnt DropCnt ResetTime Reason\n");
                                else
                                        vty_out(vty,
-                                               "V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt\n");
+                                               "V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt Desc\n");
                        }
                }
 
@@ -10810,32 +10976,81 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                                    peer->pcount[afi][pfx_rcd_safi]);
 
                                if (paf && PAF_SUBGRP(paf))
-                                       json_object_int_add(json_peer,
-                                                           "pfxSnt",
-                                                           (PAF_SUBGRP(paf))->scount);
+                                       json_object_int_add(
+                                               json_peer, "pfxSnt",
+                                               (PAF_SUBGRP(paf))->scount);
+                               else
+                                       json_object_int_add(json_peer, "pfxSnt",
+                                                           0);
+
+                               /* BGP FSM state */
                                if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)
                                    || CHECK_FLAG(peer->bgp->flags,
                                                  BGP_FLAG_SHUTDOWN))
-                                       json_object_string_add(json_peer, "state",
+                                       json_object_string_add(json_peer,
+                                                              "state",
                                                               "Idle (Admin)");
                                else if (peer->afc_recv[afi][safi])
                                        json_object_string_add(
-                                                              json_peer, "state",
-                                                              lookup_msg(bgp_status_msg, peer->status,
-                                                                         NULL));
-                               else if (CHECK_FLAG(peer->sflags,
-                                                   PEER_STATUS_PREFIX_OVERFLOW))
-                                       json_object_string_add(json_peer, "state",
+                                               json_peer, "state",
+                                               lookup_msg(bgp_status_msg,
+                                                          peer->status, NULL));
+                               else if (CHECK_FLAG(
+                                                peer->sflags,
+                                                PEER_STATUS_PREFIX_OVERFLOW))
+                                       json_object_string_add(json_peer,
+                                                              "state",
                                                               "Idle (PfxCt)");
                                else
                                        json_object_string_add(
-                                                              json_peer, "state",
-                                                              lookup_msg(bgp_status_msg, peer->status,
-                                                                         NULL));
+                                               json_peer, "state",
+                                               lookup_msg(bgp_status_msg,
+                                                          peer->status, NULL));
+
+                               /* BGP peer state */
+                               if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)
+                                   || CHECK_FLAG(peer->bgp->flags,
+                                                 BGP_FLAG_SHUTDOWN))
+                                       json_object_string_add(json_peer,
+                                                              "peerState",
+                                                              "Admin");
+                               else if (CHECK_FLAG(
+                                                peer->sflags,
+                                                PEER_STATUS_PREFIX_OVERFLOW))
+                                       json_object_string_add(json_peer,
+                                                              "peerState",
+                                                              "PfxCt");
+                               else if (CHECK_FLAG(peer->flags,
+                                                   PEER_FLAG_PASSIVE))
+                                       json_object_string_add(json_peer,
+                                                              "peerState",
+                                                              "Passive");
+                               else if (CHECK_FLAG(peer->sflags,
+                                                   PEER_STATUS_NSF_WAIT))
+                                       json_object_string_add(json_peer,
+                                                              "peerState",
+                                                              "NSF passive");
+                               else if (CHECK_FLAG(
+                                                peer->bgp->flags,
+                                                BGP_FLAG_EBGP_REQUIRES_POLICY)
+                                        && (!bgp_inbound_policy_exists(peer,
+                                                                       filter)
+                                            || !bgp_outbound_policy_exists(
+                                                    peer, filter)))
+                                       json_object_string_add(json_peer,
+                                                              "peerState",
+                                                              "Policy");
+                               else
+                                       json_object_string_add(
+                                               json_peer, "peerState", "OK");
+
                                json_object_int_add(json_peer, "connectionsEstablished",
                                                    peer->established);
                                json_object_int_add(json_peer, "connectionsDropped",
                                                    peer->dropped);
+                               if (peer->desc)
+                                       json_object_string_add(
+                                               json_peer, "desc", peer->desc);
                        }
                        /* Avoid creating empty peer dicts in JSON */
                        if (json_peer == NULL)
@@ -10950,6 +11165,10 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
 
                                        vty_out(vty, " %8u", 0);
                                }
+                               if (peer->desc)
+                                       vty_out(vty, " %s", peer->desc);
+                               else
+                                       vty_out(vty, " N/A");
                                vty_out(vty, "\n");
                        }
 
@@ -12434,9 +12653,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                        if (dn_flag[0]) {
                                struct prefix prefix, *range = NULL;
 
-                               sockunion2hostprefix(&(p->su), &prefix);
-                               range = peer_group_lookup_dynamic_neighbor_range(
-                                       p->group, &prefix);
+                               if (sockunion2hostprefix(&(p->su), &prefix))
+                                       range = peer_group_lookup_dynamic_neighbor_range(
+                                               p->group, &prefix);
 
                                if (range) {
                                        prefix2str(range, buf1, sizeof(buf1));
@@ -12453,9 +12672,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                        if (dn_flag[0]) {
                                struct prefix prefix, *range = NULL;
 
-                               sockunion2hostprefix(&(p->su), &prefix);
-                               range = peer_group_lookup_dynamic_neighbor_range(
-                                       p->group, &prefix);
+                               if (sockunion2hostprefix(&(p->su), &prefix))
+                                       range = peer_group_lookup_dynamic_neighbor_range(
+                                               p->group, &prefix);
 
                                if (range) {
                                        vty_out(vty,
@@ -12555,6 +12774,12 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                json_object_int_add(json_neigh,
                                    "bgpTimerKeepAliveIntervalMsecs",
                                    p->v_keepalive * 1000);
+               if (CHECK_FLAG(p->flags, PEER_FLAG_TIMER_DELAYOPEN)) {
+                       json_object_int_add(json_neigh,
+                                           "bgpTimerDelayOpenTimeMsecs",
+                                           p->v_delayopen * 1000);
+               }
+
                if (CHECK_FLAG(p->flags, PEER_FLAG_TIMER)) {
                        json_object_int_add(json_neigh,
                                            "bgpTimerConfiguredHoldTimeMsecs",
@@ -12634,6 +12859,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                        vty_out(vty, ", keepalive interval is %d seconds\n",
                                bgp->default_keepalive);
                }
+               if (CHECK_FLAG(p->flags, PEER_FLAG_TIMER_DELAYOPEN))
+                       vty_out(vty,
+                               "  Configured DelayOpenTime is %d seconds\n",
+                               p->delayopen);
        }
        /* Capability. */
        if (p->status == Established) {
@@ -12950,6 +13179,37 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                        "received");
                                }
 
+                               /* Enhanced Route Refresh */
+                               if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_ADV)
+                                   || CHECK_FLAG(p->cap,
+                                                 PEER_CAP_ENHANCED_RR_RCV)) {
+                                       if (CHECK_FLAG(p->cap,
+                                                      PEER_CAP_ENHANCED_RR_ADV)
+                                           && CHECK_FLAG(
+                                                   p->cap,
+                                                   PEER_CAP_ENHANCED_RR_RCV))
+                                               json_object_string_add(
+                                                       json_cap,
+                                                       "enhancedRouteRefresh",
+                                                       "advertisedAndReceived");
+                                       else if (
+                                               CHECK_FLAG(
+                                                       p->cap,
+                                                       PEER_CAP_ENHANCED_RR_ADV))
+                                               json_object_string_add(
+                                                       json_cap,
+                                                       "enhancedRouteRefresh",
+                                                       "advertised");
+                                       else if (
+                                               CHECK_FLAG(
+                                                       p->cap,
+                                                       PEER_CAP_ENHANCED_RR_RCV))
+                                               json_object_string_add(
+                                                       json_cap,
+                                                       "enhancedRouteRefresh",
+                                                       "received");
+                               }
+
                                /* Multiprotocol Extensions */
                                json_object *json_multi = NULL;
                                json_multi = json_object_new_object();
@@ -13322,6 +13582,28 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                        vty_out(vty, "\n");
                                }
 
+                               /* Enhanced Route Refresh */
+                               if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_ADV)
+                                   || CHECK_FLAG(p->cap,
+                                                 PEER_CAP_ENHANCED_RR_RCV)) {
+                                       vty_out(vty,
+                                               "    Enhanced Route Refresh:");
+                                       if (CHECK_FLAG(
+                                                   p->cap,
+                                                   PEER_CAP_ENHANCED_RR_ADV))
+                                               vty_out(vty, " advertised");
+                                       if (CHECK_FLAG(
+                                                   p->cap,
+                                                   PEER_CAP_ENHANCED_RR_RCV))
+                                               vty_out(vty, " %sreceived",
+                                                       CHECK_FLAG(
+                                                               p->cap,
+                                                               PEER_CAP_REFRESH_ADV)
+                                                               ? "and "
+                                                               : "");
+                                       vty_out(vty, "\n");
+                               }
+
                                /* Multiprotocol Extensions */
                                FOREACH_AFI_SAFI (afi, safi)
                                        if (p->afc_adv[afi][safi]
@@ -16350,6 +16632,18 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
                vty_out(vty, " neighbor %s timers connect %u\n", addr,
                        peer->bgp->default_connect_retry);
 
+       /* timers delayopen */
+       if (peergroup_flag_check(peer, PEER_FLAG_TIMER_DELAYOPEN))
+               vty_out(vty, " neighbor %s timers delayopen %u\n", addr,
+                       peer->delayopen);
+       /* Save config even though flag is not set if default values have been
+        * changed
+        */
+       else if (!peer_group_active(peer) && !peer->delayopen
+                && peer->bgp->default_delayopen != BGP_DEFAULT_DELAYOPEN)
+               vty_out(vty, " neighbor %s timers delayopen %u\n", addr,
+                       peer->bgp->default_delayopen);
+
        /* capability dynamic */
        if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY))
                vty_out(vty, " neighbor %s capability dynamic\n", addr);
@@ -16732,7 +17026,15 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
 
        /* BGP flag dampening. */
        if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
-               bgp_config_write_damp(vty, afi, safi);
+               bgp_config_write_damp(vty, bgp, afi, safi);
+       for (ALL_LIST_ELEMENTS_RO(bgp->group, node, group))
+               if (peer_af_flag_check(group->conf, afi, safi,
+                                      PEER_FLAG_CONFIG_DAMPENING))
+                       bgp_config_write_peer_damp(vty, group->conf, afi, safi);
+       for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer))
+               if (peer_af_flag_check(peer, afi, safi,
+                                      PEER_FLAG_CONFIG_DAMPENING))
+                       bgp_config_write_peer_damp(vty, peer, afi, safi);
 
        for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group))
                bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi);
@@ -16801,6 +17103,9 @@ int bgp_config_write(struct vty *vty)
                vty_out(vty, "\n");
        }
 
+       if (bm->wait_for_fib)
+               vty_out(vty, "bgp suppress-fib-pending\n");
+
        if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN))
                vty_out(vty, "bgp graceful-shutdown\n");
 
@@ -16808,6 +17113,9 @@ int bgp_config_write(struct vty *vty)
        if (bgp_option_check(BGP_OPT_NO_FIB))
                vty_out(vty, "bgp no-rib\n");
 
+       if (!CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA))
+               vty_out(vty, "no bgp send-extra-data zebra\n");
+
        /* BGP configuration. */
        for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
 
@@ -16829,7 +17137,7 @@ int bgp_config_write(struct vty *vty)
                        vty_out(vty, " no bgp fast-external-failover\n");
 
                /* BGP router ID. */
-               if (bgp->router_id_static.s_addr != 0)
+               if (bgp->router_id_static.s_addr != INADDR_ANY)
                        vty_out(vty, " bgp router-id %pI4\n",
                                &bgp->router_id_static);
 
@@ -16863,6 +17171,16 @@ int bgp_config_write(struct vty *vty)
                if (bgp->reject_as_sets)
                        vty_out(vty, " bgp reject-as-sets\n");
 
+               /* Suppress duplicate updates if the route actually not changed
+                */
+               if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES)
+                   != SAVE_BGP_SUPPRESS_DUPLICATES)
+                       vty_out(vty, " %sbgp suppress-duplicates\n",
+                               CHECK_FLAG(bgp->flags,
+                                          BGP_FLAG_SUPPRESS_DUPLICATES)
+                                       ? ""
+                                       : "no ");
+
                /* BGP default ipv4-unicast. */
                if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4))
                        vty_out(vty, " no bgp default ipv4-unicast\n");
@@ -17326,6 +17644,9 @@ void bgp_vty_init(void)
        install_element(CONFIG_NODE, &bgp_local_mac_cmd);
        install_element(CONFIG_NODE, &no_bgp_local_mac_cmd);
 
+       /* "bgp suppress-fib-pending" global */
+       install_element(CONFIG_NODE, &bgp_global_suppress_fib_pending_cmd);
+
        /* bgp route-map delay-timer commands. */
        install_element(CONFIG_NODE, &bgp_set_route_map_delay_timer_cmd);
        install_element(CONFIG_NODE, &no_bgp_set_route_map_delay_timer_cmd);
@@ -17363,6 +17684,8 @@ void bgp_vty_init(void)
        install_element(CONFIG_NODE, &bgp_norib_cmd);
        install_element(CONFIG_NODE, &no_bgp_norib_cmd);
 
+       install_element(CONFIG_NODE, &no_bgp_send_extra_data_cmd);
+
        /* "bgp confederation" commands. */
        install_element(BGP_NODE, &bgp_confederation_identifier_cmd);
        install_element(BGP_NODE, &no_bgp_confederation_identifier_cmd);
@@ -17441,6 +17764,10 @@ void bgp_vty_init(void)
        install_element(BGP_NODE, &bgp_ebgp_requires_policy_cmd);
        install_element(BGP_NODE, &no_bgp_ebgp_requires_policy_cmd);
 
+       /* bgp suppress-duplicates */
+       install_element(BGP_NODE, &bgp_suppress_duplicates_cmd);
+       install_element(BGP_NODE, &no_bgp_suppress_duplicates_cmd);
+
        /* bgp reject-as-sets */
        install_element(BGP_NODE, &bgp_reject_as_sets_cmd);
        install_element(BGP_NODE, &no_bgp_reject_as_sets_cmd);
@@ -18209,6 +18536,10 @@ void bgp_vty_init(void)
        install_element(BGP_NODE, &neighbor_timers_connect_cmd);
        install_element(BGP_NODE, &no_neighbor_timers_connect_cmd);
 
+       /* "neighbor timers delayopen" commands. */
+       install_element(BGP_NODE, &neighbor_timers_delayopen_cmd);
+       install_element(BGP_NODE, &no_neighbor_timers_delayopen_cmd);
+
        /* "neighbor advertisement-interval" commands. */
        install_element(BGP_NODE, &neighbor_advertise_interval_cmd);
        install_element(BGP_NODE, &no_neighbor_advertise_interval_cmd);
@@ -18239,27 +18570,16 @@ void bgp_vty_init(void)
 
        /* "neighbor prefix-list" commands. */
        install_element(BGP_NODE, &neighbor_prefix_list_hidden_cmd);
-       install_element(BGP_NODE, &no_neighbor_prefix_list_hidden_cmd);
        install_element(BGP_IPV4_NODE, &neighbor_prefix_list_cmd);
-       install_element(BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd);
        install_element(BGP_IPV4M_NODE, &neighbor_prefix_list_cmd);
-       install_element(BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd);
        install_element(BGP_IPV4L_NODE, &neighbor_prefix_list_cmd);
-       install_element(BGP_IPV4L_NODE, &no_neighbor_prefix_list_cmd);
        install_element(BGP_IPV6_NODE, &neighbor_prefix_list_cmd);
-       install_element(BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd);
        install_element(BGP_IPV6M_NODE, &neighbor_prefix_list_cmd);
-       install_element(BGP_IPV6M_NODE, &no_neighbor_prefix_list_cmd);
        install_element(BGP_IPV6L_NODE, &neighbor_prefix_list_cmd);
-       install_element(BGP_IPV6L_NODE, &no_neighbor_prefix_list_cmd);
        install_element(BGP_VPNV4_NODE, &neighbor_prefix_list_cmd);
-       install_element(BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd);
        install_element(BGP_VPNV6_NODE, &neighbor_prefix_list_cmd);
-       install_element(BGP_VPNV6_NODE, &no_neighbor_prefix_list_cmd);
        install_element(BGP_FLOWSPECV4_NODE, &neighbor_prefix_list_cmd);
-       install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_prefix_list_cmd);
        install_element(BGP_FLOWSPECV6_NODE, &neighbor_prefix_list_cmd);
-       install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_prefix_list_cmd);
 
        /* "neighbor filter-list" commands. */
        install_element(BGP_NODE, &neighbor_filter_list_hidden_cmd);
@@ -18289,27 +18609,16 @@ void bgp_vty_init(void)
        install_element(BGP_NODE, &neighbor_route_map_hidden_cmd);
        install_element(BGP_NODE, &no_neighbor_route_map_hidden_cmd);
        install_element(BGP_IPV4_NODE, &neighbor_route_map_cmd);
-       install_element(BGP_IPV4_NODE, &no_neighbor_route_map_cmd);
        install_element(BGP_IPV4M_NODE, &neighbor_route_map_cmd);
-       install_element(BGP_IPV4M_NODE, &no_neighbor_route_map_cmd);
        install_element(BGP_IPV4L_NODE, &neighbor_route_map_cmd);
-       install_element(BGP_IPV4L_NODE, &no_neighbor_route_map_cmd);
        install_element(BGP_IPV6_NODE, &neighbor_route_map_cmd);
-       install_element(BGP_IPV6_NODE, &no_neighbor_route_map_cmd);
        install_element(BGP_IPV6M_NODE, &neighbor_route_map_cmd);
-       install_element(BGP_IPV6M_NODE, &no_neighbor_route_map_cmd);
        install_element(BGP_IPV6L_NODE, &neighbor_route_map_cmd);
-       install_element(BGP_IPV6L_NODE, &no_neighbor_route_map_cmd);
        install_element(BGP_VPNV4_NODE, &neighbor_route_map_cmd);
-       install_element(BGP_VPNV4_NODE, &no_neighbor_route_map_cmd);
        install_element(BGP_VPNV6_NODE, &neighbor_route_map_cmd);
-       install_element(BGP_VPNV6_NODE, &no_neighbor_route_map_cmd);
        install_element(BGP_FLOWSPECV4_NODE, &neighbor_route_map_cmd);
-       install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_route_map_cmd);
        install_element(BGP_FLOWSPECV6_NODE, &neighbor_route_map_cmd);
-       install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_route_map_cmd);
        install_element(BGP_EVPN_NODE, &neighbor_route_map_cmd);
-       install_element(BGP_EVPN_NODE, &no_neighbor_route_map_cmd);
 
        /* "neighbor unsuppress-map" commands. */
        install_element(BGP_NODE, &neighbor_unsuppress_map_hidden_cmd);
@@ -18468,6 +18777,23 @@ void bgp_vty_init(void)
        install_element(BGP_EVPN_NODE, &neighbor_allowas_in_cmd);
        install_element(BGP_EVPN_NODE, &no_neighbor_allowas_in_cmd);
 
+       /* "neighbor dampening" commands. */
+       install_element(BGP_NODE, &neighbor_damp_cmd);
+       install_element(BGP_NODE, &no_neighbor_damp_cmd);
+       install_element(BGP_IPV4_NODE, &neighbor_damp_cmd);
+       install_element(BGP_IPV4_NODE, &no_neighbor_damp_cmd);
+       install_element(BGP_IPV4M_NODE, &neighbor_damp_cmd);
+       install_element(BGP_IPV4M_NODE, &no_neighbor_damp_cmd);
+       install_element(BGP_IPV4L_NODE, &neighbor_damp_cmd);
+       install_element(BGP_IPV4L_NODE, &no_neighbor_damp_cmd);
+       install_element(BGP_IPV6_NODE, &neighbor_damp_cmd);
+       install_element(BGP_IPV6_NODE, &no_neighbor_damp_cmd);
+       install_element(BGP_IPV6M_NODE, &neighbor_damp_cmd);
+       install_element(BGP_IPV6M_NODE, &no_neighbor_damp_cmd);
+       install_element(BGP_IPV6L_NODE, &neighbor_damp_cmd);
+       install_element(BGP_IPV6L_NODE, &no_neighbor_damp_cmd);
+       install_element(VIEW_NODE, &show_ip_bgp_neighbor_damp_param_cmd);
+
        /* address-family commands. */
        install_element(BGP_NODE, &address_family_ipv4_safi_cmd);
        install_element(BGP_NODE, &address_family_ipv6_safi_cmd);
index 73f03f6a9d243753ae5c51d211e6b96f7b6326cf..f7c4b04adffa5d40beb18701fab22da571d8c5dd 100644 (file)
@@ -41,6 +41,7 @@
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_route.h"
 #include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_aspath.h"
 #include "bgpd/bgp_nexthop.h"
 #include "bgpd/bgp_zebra.h"
 #include "bgpd/bgp_fsm.h"
@@ -526,10 +527,10 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS)
                        inet_ntop(api.prefix.family, &nexthop, buf,
                                  sizeof(buf));
                        zlog_debug(
-                               "Rx route ADD VRF %u %s[%d] %pFX nexthop %s (type %d if %u) metric %u tag %" ROUTE_TAG_PRI,
+                               "Rx route ADD VRF %u %s[%d] %pFX nexthop %s (type %d if %u) metric %u distance %u tag %" ROUTE_TAG_PRI,
                                vrf_id, zebra_route_string(api.type),
                                api.instance, &api.prefix, buf, nhtype, ifindex,
-                               api.metric, api.tag);
+                               api.metric, api.distance, api.tag);
                } else {
                        zlog_debug("Rx route DEL VRF %u %s[%d] %pFX", vrf_id,
                                   zebra_route_string(api.type), api.instance,
@@ -1176,9 +1177,11 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
        int nh_othervrf = 0;
        char buf_prefix[PREFIX_STRLEN]; /* filled in if we are debugging */
        bool is_evpn;
-       int nh_updated;
+       bool nh_updated = false;
        bool do_wt_ecmp;
        uint64_t cum_bw = 0;
+       uint32_t nhg_id = 0;
+       bool is_add;
 
        /* Don't try to install if we're not connected to Zebra or Zebra doesn't
         * know of this instance.
@@ -1257,7 +1260,17 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
        if (do_wt_ecmp)
                cum_bw = bgp_path_info_mpath_cumbw(info);
 
-       for (mpinfo = info; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) {
+       /* EVPN MAC-IP routes are installed with a L3 NHG id */
+       if (bgp_evpn_path_es_use_nhg(bgp, info, &nhg_id)) {
+               mpinfo = NULL;
+               api.nhgid = nhg_id;
+               if (nhg_id)
+                       SET_FLAG(api.message, ZAPI_MESSAGE_NHG);
+       } else {
+               mpinfo = info;
+       }
+
+       for (; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) {
                uint32_t nh_weight;
 
                if (valid_nh_count >= multipath_num)
@@ -1292,43 +1305,36 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
                               ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR)))
                        api_nh->srte_color = info->attr->srte_color;
 
-               if (nh_family == AF_INET) {
-                       if (bgp_debug_zebra(&api.prefix)) {
-                               if (mpinfo->extra) {
-                                       zlog_debug(
-                                               "%s: p=%s, bgp_is_valid_label: %d",
-                                               __func__, buf_prefix,
-                                               bgp_is_valid_label(
-                                                       &mpinfo->extra
-                                                                ->label[0]));
-                               } else {
-                                       zlog_debug(
-                                               "%s: p=%s, extra is NULL, no label",
-                                               __func__, buf_prefix);
-                               }
-                       }
-
-                       if (bgp->table_map[afi][safi].name) {
-                               /* Copy info and attributes, so the route-map
-                                  apply doesn't modify the BGP route info. */
-                               local_attr = *mpinfo->attr;
-                               mpinfo_cp->attr = &local_attr;
+               if (bgp_debug_zebra(&api.prefix)) {
+                       if (mpinfo->extra) {
+                               zlog_debug("%s: p=%s, bgp_is_valid_label: %d",
+                                          __func__, buf_prefix,
+                                          bgp_is_valid_label(
+                                                  &mpinfo->extra->label[0]));
+                       } else {
+                               zlog_debug("%s: p=%s, extra is NULL, no label",
+                                          __func__, buf_prefix);
                        }
+               }
 
-                       if (bgp->table_map[afi][safi].name) {
-                               if (!bgp_table_map_apply(
-                                           bgp->table_map[afi][safi].map, p,
-                                           mpinfo_cp))
-                                       continue;
+               if (bgp->table_map[afi][safi].name) {
+                       /* Copy info and attributes, so the route-map
+                          apply doesn't modify the BGP route info. */
+                       local_attr = *mpinfo->attr;
+                       mpinfo_cp->attr = &local_attr;
+                       if (!bgp_table_map_apply(bgp->table_map[afi][safi].map,
+                                                p, mpinfo_cp))
+                               continue;
 
-                               /* metric/tag is only allowed to be
-                                * overridden on 1st nexthop */
-                               if (mpinfo == info) {
-                                       metric = mpinfo_cp->attr->med;
-                                       tag = mpinfo_cp->attr->tag;
-                               }
+                       /* metric/tag is only allowed to be
+                        * overridden on 1st nexthop */
+                       if (mpinfo == info) {
+                               metric = mpinfo_cp->attr->med;
+                               tag = mpinfo_cp->attr->tag;
                        }
+               }
 
+               if (nh_family == AF_INET) {
                        nh_updated = update_ipv4nh_for_route_install(
                                        nh_othervrf,
                                        nh_othervrf ?
@@ -1339,38 +1345,23 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
                        ifindex_t ifindex = IFINDEX_INTERNAL;
                        struct in6_addr *nexthop;
 
-                       if (bgp->table_map[afi][safi].name) {
-                               /* Copy info and attributes, so the route-map
-                                  apply doesn't modify the BGP route info. */
-                               local_attr = *mpinfo->attr;
-                               mpinfo_cp->attr = &local_attr;
-                       }
-
-                       if (bgp->table_map[afi][safi].name) {
-                               /* Copy info and attributes, so the route-map
-                                  apply doesn't modify the BGP route info. */
-                               local_attr = *mpinfo->attr;
-                               mpinfo_cp->attr = &local_attr;
-
-                               if (!bgp_table_map_apply(
-                                           bgp->table_map[afi][safi].map, p,
-                                           mpinfo_cp))
-                                       continue;
-
-                               /* metric/tag is only allowed to be
-                                * overridden on 1st nexthop */
-                               if (mpinfo == info) {
-                                       metric = mpinfo_cp->attr->med;
-                                       tag = mpinfo_cp->attr->tag;
-                               }
-                       }
                        nexthop = bgp_path_info_to_ipv6_nexthop(mpinfo_cp,
                                                                &ifindex);
-                       nh_updated = update_ipv6nh_for_route_install(
-                                       nh_othervrf, nh_othervrf ?
-                                       info->extra->bgp_orig : bgp,
-                                       nexthop, ifindex,
-                                       mpinfo, info, is_evpn, api_nh);
+
+                       if (!nexthop)
+                               nh_updated = update_ipv4nh_for_route_install(
+                                       nh_othervrf,
+                                       nh_othervrf ? info->extra->bgp_orig
+                                                   : bgp,
+                                       &mpinfo_cp->attr->nexthop,
+                                       mpinfo_cp->attr, is_evpn, api_nh);
+                       else
+                               nh_updated = update_ipv6nh_for_route_install(
+                                       nh_othervrf,
+                                       nh_othervrf ? info->extra->bgp_orig
+                                                   : bgp,
+                                       nexthop, ifindex, mpinfo, info, is_evpn,
+                                       api_nh);
                }
 
                /* Did we get proper nexthop info to update zebra? */
@@ -1395,6 +1386,16 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
                valid_nh_count++;
        }
 
+       is_add = (valid_nh_count || nhg_id) ? true : false;
+
+       if (is_add && CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) {
+               struct aspath *aspath = info->attr->aspath;
+
+               SET_FLAG(api.message, ZAPI_MESSAGE_OPAQUE);
+               api.opaque.length = strlen(aspath->str) + 1;
+               memcpy(api.opaque.data, aspath->str, api.opaque.length);
+       }
+
        /*
         * When we create an aggregate route we must also
         * install a Null0 route in the RIB, so overwrite
@@ -1428,9 +1429,10 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
 
                zlog_debug(
                        "Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI
-                       " count %d",
+                       " count %d nhg %d",
                        valid_nh_count ? "add" : "delete", bgp->vrf_id,
-                       &api.prefix, api.metric, api.tag, api.nexthop_num);
+                       &api.prefix, api.metric, api.tag, api.nexthop_num,
+                       nhg_id);
                for (i = 0; i < api.nexthop_num; i++) {
                        api_nh = &api.nexthops[i];
 
@@ -1475,9 +1477,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
                                   api_nh->vrf_id, api_nh->weight,
                                   label_buf, eth_buf);
                }
-       }
 
-       if (bgp_debug_zebra(p)) {
                int recursion_flag = 0;
 
                if (CHECK_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION))
@@ -1487,8 +1487,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
                        __func__, buf_prefix,
                        (recursion_flag ? "" : "NOT "));
        }
-       zclient_route_send(valid_nh_count ? ZEBRA_ROUTE_ADD
-                                         : ZEBRA_ROUTE_DELETE,
+       zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
                           zclient, &api);
 }
 
@@ -1820,7 +1819,6 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type,
                vrf_bitmap_unset(zclient->redist[afi][type], bgp->vrf_id);
        }
 
-
        if (bgp_install_info_to_zebra(bgp)) {
                /* Send distribute delete message to zebra. */
                if (BGP_DEBUG(zebra, ZEBRA))
@@ -2387,7 +2385,6 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient,
        struct prefix p;
        enum zapi_route_notify_owner note;
        uint32_t table_id;
-       char buf[PREFIX_STRLEN];
        afi_t afi;
        safi_t safi;
        struct bgp_dest *dest;
@@ -2409,9 +2406,6 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient,
                return -1;
        }
 
-       if (BGP_DEBUG(zebra, ZEBRA))
-               prefix2str(&p, buf, sizeof(buf));
-
        /* Find the bgp route node */
        dest = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi, &p,
                                   &bgp->vrf_prd);
@@ -2430,7 +2424,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient,
                                   BGP_NODE_FIB_INSTALL_PENDING);
                        SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED);
                        if (BGP_DEBUG(zebra, ZEBRA))
-                               zlog_debug("route %s : INSTALLED", buf);
+                               zlog_debug("route %pRN : INSTALLED", dest);
                        /* Find the best route */
                        for (pi = dest->info; pi; pi = pi->next) {
                                /* Process aggregate route */
@@ -2446,8 +2440,8 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient,
                                                     dest, new_select);
                        else {
                                flog_err(EC_BGP_INVALID_ROUTE,
-                                        "selected route %s not found",
-                                        buf);
+                                        "selected route %pRN not found",
+                                        dest);
                                return -1;
                        }
                }
@@ -2458,16 +2452,24 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient,
                 * route add later
                 */
                UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED);
+               if (BGP_DEBUG(zebra, ZEBRA))
+                       zlog_debug("route %pRN: Removed from Fib", dest);
                break;
        case ZAPI_ROUTE_FAIL_INSTALL:
+               if (BGP_DEBUG(zebra, ZEBRA))
+                       zlog_debug("route: %pRN Failed to Install into Fib",
+                                  dest);
                /* Error will be logged by zebra module */
                break;
        case ZAPI_ROUTE_BETTER_ADMIN_WON:
+               if (BGP_DEBUG(zebra, ZEBRA))
+                       zlog_debug("route: %pRN removed due to better admin won",
+                                  dest);
                /* No action required */
                break;
        case ZAPI_ROUTE_REMOVE_FAIL:
-               zlog_warn("%s: Route %s failure to remove",
-                         __func__, buf);
+               zlog_warn("%s: Route %pRN failure to remove",
+                         __func__, dest);
                break;
        }
        return 0;
@@ -3051,7 +3053,8 @@ void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra,
        bgp_encode_pbr_rule_action(s, pbra, pbr);
 
        stream_putw_at(s, 0, stream_get_endp(s));
-       if (!zclient_send_message(zclient) && install) {
+       if ((zclient_send_message(zclient) != ZCLIENT_SEND_FAILURE)
+           && install) {
                if (!pbr)
                        pbra->install_in_progress = true;
                else
@@ -3082,7 +3085,7 @@ void bgp_send_pbr_ipset_match(struct bgp_pbr_match *pbrim, bool install)
        bgp_encode_pbr_ipset_match(s, pbrim);
 
        stream_putw_at(s, 0, stream_get_endp(s));
-       if (!zclient_send_message(zclient) && install)
+       if ((zclient_send_message(zclient) != ZCLIENT_SEND_FAILURE) && install)
                pbrim->install_in_progress = true;
 }
 
@@ -3110,7 +3113,7 @@ void bgp_send_pbr_ipset_entry_match(struct bgp_pbr_match_entry *pbrime,
        bgp_encode_pbr_ipset_entry_match(s, pbrime);
 
        stream_putw_at(s, 0, stream_get_endp(s));
-       if (!zclient_send_message(zclient) && install)
+       if ((zclient_send_message(zclient) != ZCLIENT_SEND_FAILURE) && install)
                pbrime->install_in_progress = true;
 }
 
@@ -3185,7 +3188,7 @@ void bgp_send_pbr_iptable(struct bgp_pbr_action *pba,
        stream_putw_at(s, 0, stream_get_endp(s));
        ret = zclient_send_message(zclient);
        if (install) {
-               if (ret)
+               if (ret != ZCLIENT_SEND_FAILURE)
                        pba->refcnt++;
                else
                        pbm->install_iptable_in_progress = true;
@@ -3319,7 +3322,7 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable)
        }
 
        if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient, &api)
-           < 0) {
+           == ZCLIENT_SEND_FAILURE) {
                zlog_err("error sending capability");
                ret = BGP_GR_FAILURE;
        } else {
@@ -3361,7 +3364,7 @@ int bgp_zebra_update(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type)
        api.cap = type;
 
        if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient, &api)
-           < 0) {
+           == ZCLIENT_SEND_FAILURE) {
                if (BGP_DEBUG(zebra, ZEBRA))
                        zlog_debug("error sending capability");
                return BGP_GR_FAILURE;
@@ -3393,7 +3396,7 @@ int bgp_zebra_stale_timer_update(struct bgp *bgp)
        api.stale_removal_time = bgp->rib_stale_time;
        api.vrf_id = bgp->vrf_id;
        if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient, &api)
-           < 0) {
+           == ZCLIENT_SEND_FAILURE) {
                if (BGP_DEBUG(zebra, ZEBRA))
                        zlog_debug("error sending capability");
                return BGP_GR_FAILURE;
index fd2c431eac4443cf5221ddc72955eccb5002c372..368397d7aa7de96d891914ef4d5f9b3dbbe7f805 100644 (file)
@@ -121,12 +121,20 @@ extern struct zclient *zclient;
 static int bgp_check_main_socket(bool create, struct bgp *bgp)
 {
        static int bgp_server_main_created;
+       struct listnode *node;
+       char *address;
 
        if (create) {
                if (bgp_server_main_created)
                        return 0;
-               if (bgp_socket(bgp, bm->port, bm->address) < 0)
-                       return BGP_ERR_INVALID_VALUE;
+               if (list_isempty(bm->addresses)) {
+                       if (bgp_socket(bgp, bm->port, NULL) < 0)
+                               return BGP_ERR_INVALID_VALUE;
+               } else {
+                       for (ALL_LIST_ELEMENTS_RO(bm->addresses, node, address))
+                               if (bgp_socket(bgp, bm->port, address) < 0)
+                                       return BGP_ERR_INVALID_VALUE;
+               }
                bgp_server_main_created = 1;
                return 0;
        }
@@ -393,6 +401,29 @@ void bgp_router_id_static_set(struct bgp *bgp, struct in_addr id)
                          true /* is config */);
 }
 
+void bm_wait_for_fib_set(bool set)
+{
+       bool send_msg = false;
+
+       if (bm->wait_for_fib == set)
+               return;
+
+       bm->wait_for_fib = set;
+       if (set) {
+               if (bgp_suppress_fib_count == 0)
+                       send_msg = true;
+               bgp_suppress_fib_count++;
+       } else {
+               bgp_suppress_fib_count--;
+               if (bgp_suppress_fib_count == 0)
+                       send_msg = true;
+       }
+
+       if (send_msg && zclient)
+               zebra_route_notify_send(ZEBRA_ROUTE_NOTIFY_REQUEST,
+                                       zclient, set);
+}
+
 /* Set the suppress fib pending for the bgp configuration */
 void bgp_suppress_fib_pending_set(struct bgp *bgp, bool set)
 {
@@ -491,12 +522,13 @@ time_t bgp_clock(void)
 
 /* BGP timer configuration.  */
 void bgp_timers_set(struct bgp *bgp, uint32_t keepalive, uint32_t holdtime,
-                   uint32_t connect_retry)
+                   uint32_t connect_retry, uint32_t delayopen)
 {
        bgp->default_keepalive =
                (keepalive < holdtime / 3 ? keepalive : holdtime / 3);
        bgp->default_holdtime = holdtime;
        bgp->default_connect_retry = connect_retry;
+       bgp->default_delayopen = delayopen;
 }
 
 /* mostly for completeness - CLI uses its own defaults */
@@ -505,6 +537,7 @@ void bgp_timers_unset(struct bgp *bgp)
        bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
        bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
        bgp->default_connect_retry = BGP_DEFAULT_CONNECT_RETRY;
+       bgp->default_delayopen = BGP_DEFAULT_DELAYOPEN;
 }
 
 /* BGP confederation configuration.  */
@@ -1410,10 +1443,12 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
        peer_dst->holdtime = peer_src->holdtime;
        peer_dst->keepalive = peer_src->keepalive;
        peer_dst->connect = peer_src->connect;
+       peer_dst->delayopen = peer_src->delayopen;
        peer_dst->v_holdtime = peer_src->v_holdtime;
        peer_dst->v_keepalive = peer_src->v_keepalive;
        peer_dst->routeadv = peer_src->routeadv;
        peer_dst->v_routeadv = peer_src->v_routeadv;
+       peer_dst->v_delayopen = peer_src->v_delayopen;
 
        /* password apply */
        if (peer_src->password && !peer_dst->password)
@@ -2352,6 +2387,14 @@ int peer_delete(struct peer *peer)
 
        bgp_bfd_deregister_peer(peer);
 
+       /* Delete peer route flap dampening configuration. This needs to happen
+        * before removing the peer from peer groups.
+        */
+       FOREACH_AFI_SAFI (afi, safi)
+               if (peer_af_flag_check(peer, afi, safi,
+                                      PEER_FLAG_CONFIG_DAMPENING))
+                       bgp_peer_damp_disable(peer, afi, safi);
+
        /* If this peer belongs to peer group, clear up the
           relationship.  */
        if (peer->group) {
@@ -2577,6 +2620,14 @@ static void peer_group2peer_config_copy(struct peer_group *group,
                        peer->v_connect = peer->bgp->default_connect_retry;
        }
 
+       if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_TIMER_DELAYOPEN)) {
+               PEER_ATTR_INHERIT(peer, group, delayopen);
+               if (CHECK_FLAG(conf->flags, PEER_FLAG_TIMER_DELAYOPEN))
+                       peer->v_delayopen = conf->delayopen;
+               else
+                       peer->v_delayopen = peer->bgp->default_delayopen;
+       }
+
        /* advertisement-interval apply */
        if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_ROUTEADV)) {
                PEER_ATTR_INHERIT(peer, group, routeadv);
@@ -2802,8 +2853,8 @@ int peer_group_listen_range_del(struct peer_group *group, struct prefix *range)
                if (!peer_dynamic_neighbor(peer))
                        continue;
 
-               sockunion2hostprefix(&peer->su, &prefix2);
-               if (prefix_match(prefix, &prefix2)) {
+               if (sockunion2hostprefix(&peer->su, &prefix2)
+                   && prefix_match(prefix, &prefix2)) {
                        if (bgp_debug_neighbor_events(peer))
                                zlog_debug(
                                        "Deleting dynamic neighbor %s group %s upon delete of listen range %pFX",
@@ -3156,6 +3207,7 @@ static struct bgp *bgp_create(as_t *as, const char *name,
                                 sizeof(struct bgp_evpn_info));
 
        bgp_evpn_init(bgp);
+       bgp_evpn_vrf_es_init(bgp);
        bgp_pbr_init(bgp);
 
        /*initilize global GR FSM */
@@ -3244,7 +3296,8 @@ struct bgp *bgp_get_evpn(void)
 int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, vrf_id_t old_vrf_id,
                      bool create)
 {
-       int ret = 0;
+       struct listnode *node;
+       char *address;
 
        /* Create BGP server socket, if listen mode not disabled */
        if (!bgp || bgp_option_check(BGP_OPT_NO_LISTEN))
@@ -3273,9 +3326,14 @@ int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, vrf_id_t old_vrf_id,
                 */
                if (vrf->vrf_id == VRF_UNKNOWN)
                        return 0;
-               ret = bgp_socket(bgp, bm->port, bm->address);
-               if (ret < 0)
-                       return BGP_ERR_INVALID_VALUE;
+               if (list_isempty(bm->addresses)) {
+                       if (bgp_socket(bgp, bm->port, NULL) < 0)
+                               return BGP_ERR_INVALID_VALUE;
+               } else {
+                       for (ALL_LIST_ELEMENTS_RO(bm->addresses, node, address))
+                               if (bgp_socket(bgp, bm->port, address) < 0)
+                                       return BGP_ERR_INVALID_VALUE;
+               }
                return 0;
        } else
                return bgp_check_main_socket(create, bgp);
@@ -3464,6 +3522,11 @@ int bgp_delete(struct bgp *bgp)
                BGP_TIMER_OFF(gr_info->t_route_select);
        }
 
+       /* Delete route flap dampening configuration */
+       FOREACH_AFI_SAFI (afi, safi) {
+               bgp_damp_disable(bgp, afi, safi);
+       }
+
        if (BGP_DEBUG(zebra, ZEBRA)) {
                if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
                        zlog_debug("Deleting Default VRF");
@@ -3834,7 +3897,8 @@ struct peer *peer_lookup_dynamic_neighbor(struct bgp *bgp, union sockunion *su)
        int dncount;
        char buf[PREFIX2STR_BUFFER];
 
-       sockunion2hostprefix(su, &prefix);
+       if (!sockunion2hostprefix(su, &prefix))
+               return NULL;
 
        /* See if incoming connection matches a configured listen range. */
        group = peer_group_lookup_dynamic_neighbor(bgp, &prefix, &listen_range);
@@ -3953,6 +4017,8 @@ bool peer_active_nego(struct peer *peer)
 void peer_change_action(struct peer *peer, afi_t afi, safi_t safi,
                               enum peer_change_type type)
 {
+       struct peer_af *paf;
+
        if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
                return;
 
@@ -3973,7 +4039,8 @@ void peer_change_action(struct peer *peer, afi_t afi, safi_t safi,
        } else if (type == peer_change_reset_in) {
                if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV)
                    || CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV))
-                       bgp_route_refresh_send(peer, afi, safi, 0, 0, 0);
+                       bgp_route_refresh_send(peer, afi, safi, 0, 0, 0,
+                                              BGP_ROUTE_REFRESH_NORMAL);
                else {
                        if ((peer->doppelganger)
                            && (peer->doppelganger->status != Deleted)
@@ -3985,7 +4052,12 @@ void peer_change_action(struct peer *peer, afi_t afi, safi_t safi,
                                        BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                }
        } else if (type == peer_change_reset_out) {
-               update_group_adjust_peer(peer_af_find(peer, afi, safi));
+               paf = peer_af_find(peer, afi, safi);
+               if (paf && paf->subgroup)
+                       SET_FLAG(paf->subgroup->sflags,
+                                SUBGRP_STATUS_FORCE_UPDATES);
+
+               update_group_adjust_peer(paf);
                bgp_announce_route(peer, afi, safi);
        }
 }
@@ -4016,6 +4088,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
        {PEER_FLAG_ROUTEADV, 0, peer_change_none},
        {PEER_FLAG_TIMER, 0, peer_change_none},
        {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},
@@ -4994,20 +5067,20 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi)
                        continue;
 
                /* Remove flag and configuration on peer-group member. */
-               UNSET_FLAG(peer->af_flags[afi][safi],
+               UNSET_FLAG(member->af_flags[afi][safi],
                           PEER_FLAG_DEFAULT_ORIGINATE);
-               if (peer->default_rmap[afi][safi].name)
+               if (member->default_rmap[afi][safi].name)
                        XFREE(MTYPE_ROUTE_MAP_NAME,
-                             peer->default_rmap[afi][safi].name);
-               route_map_counter_decrement(peer->default_rmap[afi][safi].map);
-               peer->default_rmap[afi][safi].name = NULL;
-               peer->default_rmap[afi][safi].map = NULL;
+                             member->default_rmap[afi][safi].name);
+               route_map_counter_decrement(member->default_rmap[afi][safi].map);
+               member->default_rmap[afi][safi].name = NULL;
+               member->default_rmap[afi][safi].map = NULL;
 
                /* Update peer route announcements. */
-               if (peer->status == Established && peer->afc_nego[afi][safi]) {
-                       update_group_adjust_peer(peer_af_find(peer, afi, safi));
-                       bgp_default_originate(peer, afi, safi, 1);
-                       bgp_announce_route(peer, afi, safi);
+               if (member->status == Established && member->afc_nego[afi][safi]) {
+                       update_group_adjust_peer(peer_af_find(member, afi, safi));
+                       bgp_default_originate(member, afi, safi, 1);
+                       bgp_announce_route(member, afi, safi);
                }
        }
 
@@ -5045,7 +5118,8 @@ static void peer_on_policy_change(struct peer *peer, afi_t afi, safi_t safi,
                        bgp_soft_reconfig_in(peer, afi, safi);
                else if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV)
                         || CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV))
-                       bgp_route_refresh_send(peer, afi, safi, 0, 0, 0);
+                       bgp_route_refresh_send(peer, afi, safi, 0, 0, 0,
+                                              BGP_ROUTE_REFRESH_NORMAL);
        }
 }
 
@@ -5401,6 +5475,90 @@ int peer_advertise_interval_unset(struct peer *peer)
        return 0;
 }
 
+/* set the peers RFC 4271 DelayOpen session attribute flag and DelayOpenTimer
+ * interval
+ */
+int peer_timers_delayopen_set(struct peer *peer, uint32_t delayopen)
+{
+       struct peer *member;
+       struct listnode *node;
+
+       /* Set peers session attribute flag and timer interval. */
+       peer_flag_set(peer, PEER_FLAG_TIMER_DELAYOPEN);
+       peer->delayopen = delayopen;
+       peer->v_delayopen = delayopen;
+
+       /* Skip 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
+        * explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS_RO(peer->group->peer, node, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override,
+                              PEER_FLAG_TIMER_DELAYOPEN))
+                       continue;
+
+               /* Set session attribute flag and timer intervals on peer-group
+                * member.
+                */
+               SET_FLAG(member->flags, PEER_FLAG_TIMER_DELAYOPEN);
+               member->delayopen = delayopen;
+               member->v_delayopen = delayopen;
+       }
+
+       return 0;
+}
+
+/* unset the peers RFC 4271 DelayOpen session attribute flag and reset the
+ * DelayOpenTimer interval to the default value.
+ */
+int peer_timers_delayopen_unset(struct peer *peer)
+{
+       struct peer *member;
+       struct listnode *node;
+
+       /* Inherit configuration from peer-group if peer is member. */
+       if (peer_group_active(peer)) {
+               peer_flag_inherit(peer, PEER_FLAG_TIMER_DELAYOPEN);
+               PEER_ATTR_INHERIT(peer, peer->group, delayopen);
+       } else {
+               /* Otherwise remove session attribute flag and set timer
+                * interval to default value.
+                */
+               peer_flag_unset(peer, PEER_FLAG_TIMER_DELAYOPEN);
+               peer->delayopen = peer->bgp->default_delayopen;
+       }
+
+       /* Set timer value to zero */
+       peer->v_delayopen = 0;
+
+       /* Skip peer-group mechanics for regular peers. */
+       if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+               return 0;
+
+       /* Remove flag and configuration from all peer-group members, unless
+        * they are explicitely overriding peer-group configuration.
+        */
+       for (ALL_LIST_ELEMENTS_RO(peer->group->peer, node, member)) {
+               /* Skip peers with overridden configuration. */
+               if (CHECK_FLAG(member->flags_override,
+                              PEER_FLAG_TIMER_DELAYOPEN))
+                       continue;
+
+               /* Remove session attribute flag, reset the timer interval to
+                * the default value and set the timer value to zero.
+                */
+               UNSET_FLAG(member->flags, PEER_FLAG_TIMER_DELAYOPEN);
+               member->delayopen = peer->bgp->default_delayopen;
+               member->v_delayopen = 0;
+       }
+
+       return 0;
+}
+
 /* neighbor interface */
 void peer_interface_set(struct peer *peer, const char *str)
 {
@@ -6816,6 +6974,22 @@ int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi,
        return 0;
 }
 
+static bool peer_maximum_prefix_clear_overflow(struct peer *peer)
+{
+       if (!CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
+               return false;
+
+       UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
+       if (peer->t_pmax_restart) {
+               BGP_TIMER_OFF(peer->t_pmax_restart);
+               if (bgp_debug_neighbor_events(peer))
+                       zlog_debug("%s Maximum-prefix restart timer cancelled",
+                                  peer->host);
+       }
+       BGP_EVENT_ADD(peer, BGP_Start);
+       return true;
+}
+
 int peer_maximum_prefix_set(struct peer *peer, afi_t afi, safi_t safi,
                            uint32_t max, uint8_t threshold, int warning,
                            uint16_t restart, bool force)
@@ -6937,7 +7111,11 @@ int peer_maximum_prefix_unset(struct peer *peer, afi_t afi, safi_t safi)
                        member->pmax[afi][safi] = 0;
                        member->pmax_threshold[afi][safi] = 0;
                        member->pmax_restart[afi][safi] = 0;
+
+                       peer_maximum_prefix_clear_overflow(member);
                }
+       } else {
+               peer_maximum_prefix_clear_overflow(peer);
        }
 
        return 0;
@@ -6972,6 +7150,7 @@ int is_ebgp_multihop_configured(struct peer *peer)
 int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops)
 {
        struct peer_group *group;
+       struct peer *gpeer;
        struct listnode *node, *nnode;
        int ret;
 
@@ -7008,9 +7187,10 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops)
                                return ret;
                } else {
                        group = peer->group;
+                       group->conf->gtsm_hops = gtsm_hops;
                        for (ALL_LIST_ELEMENTS(group->peer, node, nnode,
-                                              peer)) {
-                               peer->gtsm_hops = group->conf->gtsm_hops;
+                                              gpeer)) {
+                               gpeer->gtsm_hops = group->conf->gtsm_hops;
 
                                /* Calling ebgp multihop also resets the
                                 * session.
@@ -7020,7 +7200,7 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops)
                                 * value is
                                 * irrelevant.
                                 */
-                               peer_ebgp_multihop_set(peer, MAXTTL);
+                               peer_ebgp_multihop_set(gpeer, MAXTTL);
                        }
                }
        } else {
@@ -7041,9 +7221,10 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops)
                                               MAXTTL + 1 - gtsm_hops);
                } else {
                        group = peer->group;
+                       group->conf->gtsm_hops = gtsm_hops;
                        for (ALL_LIST_ELEMENTS(group->peer, node, nnode,
-                                              peer)) {
-                               peer->gtsm_hops = group->conf->gtsm_hops;
+                                              gpeer)) {
+                               gpeer->gtsm_hops = group->conf->gtsm_hops;
 
                                /* Change setting of existing peer
                                 *   established then change value (may break
@@ -7053,17 +7234,18 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops)
                                 *   no session then do nothing (will get
                                 * handled by next connection)
                                 */
-                               if (peer->fd >= 0
-                                   && peer->gtsm_hops
+                               if (gpeer->fd >= 0
+                                   && gpeer->gtsm_hops
                                               != BGP_GTSM_HOPS_DISABLED)
                                        sockopt_minttl(
-                                               peer->su.sa.sa_family, peer->fd,
-                                               MAXTTL + 1 - peer->gtsm_hops);
-                               if ((peer->status < Established)
-                                   && peer->doppelganger
-                                   && (peer->doppelganger->fd >= 0))
-                                       sockopt_minttl(peer->su.sa.sa_family,
-                                                      peer->doppelganger->fd,
+                                               gpeer->su.sa.sa_family,
+                                               gpeer->fd,
+                                               MAXTTL + 1 - gpeer->gtsm_hops);
+                               if ((gpeer->status < Established)
+                                   && gpeer->doppelganger
+                                   && (gpeer->doppelganger->fd >= 0))
+                                       sockopt_minttl(gpeer->su.sa.sa_family,
+                                                      gpeer->doppelganger->fd,
                                                       MAXTTL + 1 - gtsm_hops);
                        }
                }
@@ -7140,18 +7322,8 @@ int peer_clear(struct peer *peer, struct listnode **nnode)
 {
        if (!CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)
            || !CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SHUTDOWN)) {
-               if (CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) {
-                       UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
-                       if (peer->t_pmax_restart) {
-                               BGP_TIMER_OFF(peer->t_pmax_restart);
-                               if (bgp_debug_neighbor_events(peer))
-                                       zlog_debug(
-                                               "%s Maximum-prefix restart timer canceled",
-                                               peer->host);
-                       }
-                       BGP_EVENT_ADD(peer, BGP_Start);
+               if (peer_maximum_prefix_clear_overflow(peer))
                        return 0;
-               }
 
                peer->v_start = BGP_INIT_START_TIMER;
                if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
@@ -7209,19 +7381,23 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi,
                                               PEER_STATUS_ORF_PREFIX_SEND))
                                        bgp_route_refresh_send(
                                                peer, afi, safi, prefix_type,
-                                               REFRESH_DEFER, 1);
-                               bgp_route_refresh_send(peer, afi, safi,
-                                                      prefix_type,
-                                                      REFRESH_IMMEDIATE, 0);
+                                               REFRESH_DEFER, 1,
+                                               BGP_ROUTE_REFRESH_NORMAL);
+                               bgp_route_refresh_send(
+                                       peer, afi, safi, prefix_type,
+                                       REFRESH_IMMEDIATE, 0,
+                                       BGP_ROUTE_REFRESH_NORMAL);
                        } else {
                                if (CHECK_FLAG(peer->af_sflags[afi][safi],
                                               PEER_STATUS_ORF_PREFIX_SEND))
                                        bgp_route_refresh_send(
                                                peer, afi, safi, prefix_type,
-                                               REFRESH_IMMEDIATE, 1);
+                                               REFRESH_IMMEDIATE, 1,
+                                               BGP_ROUTE_REFRESH_NORMAL);
                                else
-                                       bgp_route_refresh_send(peer, afi, safi,
-                                                              0, 0, 0);
+                                       bgp_route_refresh_send(
+                                               peer, afi, safi, 0, 0, 0,
+                                               BGP_ROUTE_REFRESH_NORMAL);
                        }
                        return 0;
                }
@@ -7240,8 +7416,9 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi,
                           message to the peer. */
                        if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV)
                            || CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV))
-                               bgp_route_refresh_send(peer, afi, safi, 0, 0,
-                                                      0);
+                               bgp_route_refresh_send(
+                                       peer, afi, safi, 0, 0, 0,
+                                       BGP_ROUTE_REFRESH_NORMAL);
                        else
                                return BGP_ERR_SOFT_RECONFIG_UNCONFIGURED;
                }
@@ -7296,7 +7473,8 @@ char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json,
        return buf;
 }
 
-void bgp_master_init(struct thread_master *master, const int buffer_size)
+void bgp_master_init(struct thread_master *master, const int buffer_size,
+                    struct list *addresses)
 {
        qobj_init();
 
@@ -7306,6 +7484,7 @@ void bgp_master_init(struct thread_master *master, const int buffer_size)
        bm->bgp = list_new();
        bm->listen_sockets = list_new();
        bm->port = BGP_PORT_DEFAULT;
+       bm->addresses = addresses;
        bm->master = master;
        bm->start_time = bgp_clock();
        bm->t_rmap_update = NULL;
@@ -7314,6 +7493,9 @@ void bgp_master_init(struct thread_master *master, const int buffer_size)
        bm->v_establish_wait = BGP_UPDATE_DELAY_DEF;
        bm->terminating = false;
        bm->socket_buffer = buffer_size;
+       bm->wait_for_fib = false;
+
+       SET_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA);
 
        bgp_mac_init();
        /* init the rd id space.
@@ -7326,6 +7508,7 @@ void bgp_master_init(struct thread_master *master, const int buffer_size)
        /* mpls label dynamic allocation pool */
        bgp_lp_init(bm->master, &bm->labelpool);
 
+       bgp_l3nhg_init();
        bgp_evpn_mh_init();
        QOBJ_REG(bm, bgp_master);
 }
@@ -7487,6 +7670,8 @@ void bgp_init(unsigned short instance)
        /* BFD init */
        bgp_bfd_init();
 
+       bgp_lp_vty_init();
+
        cmd_variable_handler_register(bgp_viewvrf_var_handlers);
 }
 
index d22fd008d8f561f1b8a24b5474965532024f169a..9089608062aa5128dc8ced5dccc9f756d4e306f2 100644 (file)
@@ -43,6 +43,7 @@
 #include "bgp_labelpool.h"
 #include "bgp_addpath_types.h"
 #include "bgp_nexthop.h"
+#include "bgp_damp.h"
 
 #define BGP_MAX_HOSTNAME 64    /* Linux max, is larger than most other sys */
 #define BGP_PEER_MAX_HASH_SIZE 16384
@@ -124,8 +125,8 @@ struct bgp_master {
        /* BGP port number.  */
        uint16_t port;
 
-       /* Listener address */
-       char *address;
+       /* Listener addresses */
+       struct list *addresses;
 
        /* The Mac table */
        struct hash *self_mac_hash;
@@ -159,6 +160,9 @@ struct bgp_master {
        /* How big should we set the socket buffer size */
        uint32_t socket_buffer;
 
+       /* Should we do wait for fib install globally? */
+       bool wait_for_fib;
+
        /* EVPN multihoming */
        struct bgp_evpn_mh_info *mh_info;
 
@@ -168,6 +172,7 @@ struct bgp_master {
 
        uint32_t flags;
 #define BM_FLAG_GRACEFUL_SHUTDOWN        (1 << 0)
+#define BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA (1 << 1)
 
        bool terminating;       /* global flag that sigint terminate seen */
        QOBJ_FIELDS
@@ -302,6 +307,9 @@ enum bgp_link_bw_handling {
        BGP_LINK_BW_DEFWT_4_MISSING
 };
 
+RB_HEAD(bgp_es_vrf_rb_head, bgp_evpn_es_vrf);
+RB_PROTOTYPE(bgp_es_vrf_rb_head, bgp_evpn_es_vrf, rb_node, bgp_es_vrf_rb_cmp);
+
 /* BGP instance structure.  */
 struct bgp {
        /* AS number of this BGP instance.  */
@@ -457,6 +465,7 @@ struct bgp {
 /* This flag is set if the instance is in administrative shutdown */
 #define BGP_FLAG_SHUTDOWN                 (1 << 27)
 #define BGP_FLAG_SUPPRESS_FIB_PENDING     (1 << 28)
+#define BGP_FLAG_SUPPRESS_DUPLICATES      (1 << 29)
 
        enum global_mode GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE]
                                      [BGP_GLOBAL_GR_EVENT_CMD];
@@ -557,6 +566,7 @@ struct bgp {
        uint32_t default_holdtime;
        uint32_t default_keepalive;
        uint32_t default_connect_retry;
+       uint32_t default_delayopen;
 
        /* BGP graceful restart */
        uint32_t restart_time;
@@ -637,6 +647,9 @@ struct bgp {
        /* SVI associated with the L3-VNI corresponding to this vrf */
        ifindex_t l3vni_svi_ifindex;
 
+       /* RB tree of ES-VRFs */
+       struct bgp_es_vrf_rb_head es_vrf_rb_tree;
+
        /* vrf flags */
        uint32_t vrf_flags;
 #define BGP_VRF_AUTO                        (1 << 0)
@@ -683,6 +696,9 @@ struct bgp {
        uint32_t condition_filter_count;
        struct thread *t_condition_check;
 
+       /* BGP route flap dampening configuration */
+       struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
+
        QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(bgp)
@@ -709,8 +725,9 @@ struct afi_safi_info {
 #define BGP_SELECT_DEFER_DISABLE(bgp)                                          \
        (CHECK_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE))
 
-#define BGP_SUPPRESS_FIB_ENABLED(bgp)                                         \
-       (CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_FIB_PENDING))
+#define BGP_SUPPRESS_FIB_ENABLED(bgp)                                          \
+       (CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_FIB_PENDING)                 \
+        || bm->wait_for_fib)
 
 /* BGP peer-group support. */
 struct peer_group {
@@ -898,12 +915,14 @@ enum bgp_fsm_events {
        BGP_Start = 1,
        BGP_Stop,
        TCP_connection_open,
+       TCP_connection_open_w_delay,
        TCP_connection_closed,
        TCP_connection_open_failed,
        TCP_fatal_error,
        ConnectRetry_timer_expired,
        Hold_Timer_expired,
        KeepAlive_timer_expired,
+       DelayOpen_timer_expired,
        Receive_OPEN_message,
        Receive_KEEPALIVE_message,
        Receive_UPDATE_message,
@@ -1048,6 +1067,8 @@ struct peer {
 #define PEER_CAP_ENHE_RCV                   (1U << 14) /* Extended nexthop received */
 #define PEER_CAP_HOSTNAME_ADV               (1U << 15) /* hostname advertised */
 #define PEER_CAP_HOSTNAME_RCV               (1U << 16) /* hostname received */
+#define PEER_CAP_ENHANCED_RR_ADV (1U << 17) /* enhanced rr advertised */
+#define PEER_CAP_ENHANCED_RR_RCV (1U << 18) /* enhanced rr received */
 
        /* Capability flags (reset in bgp_stop) */
        uint32_t af_cap[AFI_MAX][SAFI_MAX];
@@ -1160,6 +1181,8 @@ struct peer {
         *and PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT
         */
 
+#define PEER_FLAG_TIMER_DELAYOPEN (1 << 27) /* delayopen timer */
+
        struct bgp_peer_gr PEER_GR_FSM[BGP_PEER_GR_MODE][BGP_PEER_GR_EVENT_CMD];
        enum peer_mode peer_gr_present_state;
        /* Non stop forwarding afi-safi count for BGP gr feature*/
@@ -1180,6 +1203,9 @@ struct peer {
        /* Last update packet sent time */
        time_t pkt_stime[AFI_MAX][SAFI_MAX];
 
+       /* Peer / peer group route flap dampening configuration */
+       struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
+
        /* Peer Per AF flags */
        /*
         * Please consult the comments for *flags_override*, *flags_invert* and
@@ -1217,6 +1243,8 @@ struct peer {
 #define PEER_FLAG_SEND_LARGE_COMMUNITY      (1U << 26) /* Send large Communities */
 #define PEER_FLAG_MAX_PREFIX_OUT            (1U << 27) /* outgoing maximum prefix */
 #define PEER_FLAG_MAX_PREFIX_FORCE          (1U << 28) /* maximum-prefix <num> force */
+#define PEER_FLAG_CONFIG_DAMPENING (1U << 29) /* route flap dampening */
+
 
        enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
 
@@ -1247,12 +1275,18 @@ struct peer {
 #define PEER_STATUS_PREFIX_LIMIT      (1U << 3) /* exceed prefix-limit */
 #define PEER_STATUS_EOR_SEND          (1U << 4) /* end-of-rib send to peer */
 #define PEER_STATUS_EOR_RECEIVED      (1U << 5) /* end-of-rib received from peer */
+#define PEER_STATUS_ENHANCED_REFRESH (1U << 6) /* Enhanced Route Refresh */
+#define PEER_STATUS_BORR_SEND (1U << 7) /* BoRR send to peer */
+#define PEER_STATUS_BORR_RECEIVED (1U << 8) /* BoRR received from peer */
+#define PEER_STATUS_EORR_SEND (1U << 9) /* EoRR send to peer */
+#define PEER_STATUS_EORR_RECEIVED (1U << 10) /* EoRR received from peer */
 
        /* Configured timer values. */
        _Atomic uint32_t holdtime;
        _Atomic uint32_t keepalive;
        _Atomic uint32_t connect;
        _Atomic uint32_t routeadv;
+       _Atomic uint32_t delayopen;
 
        /* Timer values. */
        _Atomic uint32_t v_start;
@@ -1260,6 +1294,7 @@ struct peer {
        _Atomic uint32_t v_holdtime;
        _Atomic uint32_t v_keepalive;
        _Atomic uint32_t v_routeadv;
+       _Atomic uint32_t v_delayopen;
        _Atomic uint32_t v_pmax_restart;
        _Atomic uint32_t v_gr_restart;
 
@@ -1272,11 +1307,13 @@ struct peer {
        struct thread *t_connect;
        struct thread *t_holdtime;
        struct thread *t_routeadv;
+       struct thread *t_delayopen;
        struct thread *t_pmax_restart;
        struct thread *t_gr_restart;
        struct thread *t_gr_stale;
        struct thread *t_generate_updgrp_packets;
        struct thread *t_process_packet;
+       struct thread *t_refresh_stalepath;
 
        /* Thread flags. */
        _Atomic uint32_t thread_flags;
@@ -1601,7 +1638,7 @@ struct bgp_nlri {
 #define BGP_NOTIFY_HOLD_ERR                      4
 #define BGP_NOTIFY_FSM_ERR                       5
 #define BGP_NOTIFY_CEASE                         6
-#define BGP_NOTIFY_CAPABILITY_ERR                7
+#define BGP_NOTIFY_ROUTE_REFRESH_ERR             7
 
 /* Subcodes for BGP Finite State Machine Error */
 #define BGP_NOTIFY_FSM_ERR_SUBCODE_UNSPECIFIC  0
@@ -1649,10 +1686,13 @@ struct bgp_nlri {
 #define BGP_NOTIFY_CEASE_COLLISION_RESOLUTION    7
 #define BGP_NOTIFY_CEASE_OUT_OF_RESOURCE         8
 
-/* BGP_NOTIFY_CAPABILITY_ERR sub codes (draft-ietf-idr-dynamic-cap-02). */
-#define BGP_NOTIFY_CAPABILITY_INVALID_ACTION     1
-#define BGP_NOTIFY_CAPABILITY_INVALID_LENGTH     2
-#define BGP_NOTIFY_CAPABILITY_MALFORMED_CODE     3
+/* BGP_NOTIFY_ROUTE_REFRESH_ERR sub codes (RFC 7313). */
+#define BGP_NOTIFY_ROUTE_REFRESH_INVALID_MSG_LEN 1
+
+/* BGP route refresh optional subtypes. */
+#define BGP_ROUTE_REFRESH_NORMAL 0
+#define BGP_ROUTE_REFRESH_BORR 1
+#define BGP_ROUTE_REFRESH_EORR 2
 
 /* BGP timers default value.  */
 #define BGP_INIT_START_TIMER                     1
@@ -1667,6 +1707,9 @@ struct bgp_nlri {
 #define BGP_DEFAULT_EBGP_ROUTEADV                0
 #define BGP_DEFAULT_IBGP_ROUTEADV                0
 
+/* BGP RFC 4271 DelayOpenTime default value */
+#define BGP_DEFAULT_DELAYOPEN 120
+
 /* BGP default local preference.  */
 #define BGP_DEFAULT_LOCAL_PREF                 100
 
@@ -1829,8 +1872,8 @@ extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json,
 
 extern int bgp_config_write(struct vty *);
 
-extern void bgp_master_init(struct thread_master *master,
-                           const int buffer_size);
+extern void bgp_master_init(struct thread_master *master, const int buffer_size,
+                           struct list *addresses);
 
 extern void bgp_init(unsigned short instance);
 extern void bgp_pthreads_run(void);
@@ -1859,6 +1902,7 @@ extern int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf,
 extern void bgp_router_id_zebra_bump(vrf_id_t, const struct prefix *);
 extern void bgp_router_id_static_set(struct bgp *, struct in_addr);
 
+extern void bm_wait_for_fib_set(bool set);
 extern void bgp_suppress_fib_pending_set(struct bgp *bgp, bool set);
 extern int bgp_cluster_id_set(struct bgp *, struct in_addr *);
 extern int bgp_cluster_id_unset(struct bgp *);
@@ -1871,7 +1915,7 @@ extern int bgp_confederation_peers_add(struct bgp *, as_t);
 extern int bgp_confederation_peers_remove(struct bgp *, as_t);
 
 extern void bgp_timers_set(struct bgp *, uint32_t keepalive, uint32_t holdtime,
-                          uint32_t connect_retry);
+                          uint32_t connect_retry, uint32_t delayopen);
 extern void bgp_timers_unset(struct bgp *);
 
 extern int bgp_default_local_preference_set(struct bgp *, uint32_t);
@@ -1947,6 +1991,9 @@ extern int peer_timers_connect_unset(struct peer *);
 extern int peer_advertise_interval_set(struct peer *, uint32_t);
 extern int peer_advertise_interval_unset(struct peer *);
 
+extern int peer_timers_delayopen_set(struct peer *peer, uint32_t delayopen);
+extern int peer_timers_delayopen_unset(struct peer *peer);
+
 extern void peer_interface_set(struct peer *, const char *);
 extern void peer_interface_unset(struct peer *);
 
index 3d87b6354238aee121cb18a00eef15f80ca3ee14..b2732a40b4857cc1fd698a4d6bddacfc622d1c05 100644 (file)
@@ -984,7 +984,7 @@ static int rfapiEcommunitiesMatchBeec(struct ecommunity *ecom,
 
 int rfapiEcommunitiesIntersect(struct ecommunity *e1, struct ecommunity *e2)
 {
-       int i, j;
+       uint32_t i, j;
 
        if (!e1 || !e2)
                return 0;
@@ -1014,7 +1014,8 @@ int rfapiEcommunitiesIntersect(struct ecommunity *e1, struct ecommunity *e2)
 int rfapiEcommunityGetLNI(struct ecommunity *ecom, uint32_t *lni)
 {
        if (ecom) {
-               int i;
+               uint32_t i;
+
                for (i = 0; i < ecom->size; ++i) {
                        uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE);
 
@@ -1034,7 +1035,8 @@ int rfapiEcommunityGetEthernetTag(struct ecommunity *ecom, uint16_t *tag_id)
        struct bgp *bgp = bgp_get_default();
        *tag_id = 0; /* default to untagged */
        if (ecom) {
-               int i;
+               uint32_t i;
+
                for (i = 0; i < ecom->size; ++i) {
                        as_t as = 0;
                        int encode = 0;
index 68caba600a009a3c5b2c2e577d86c3613ad5984b..e24d62def4446a405aec28896e30a2811b2271ba 100644 (file)
@@ -255,7 +255,7 @@ struct rfapi {
 
 #define RFAPI_0_PREFIX(prefix)                                                 \
        ((((prefix)->family == AF_INET)                                        \
-                 ? (prefix)->u.prefix4.s_addr == 0                            \
+                 ? (prefix)->u.prefix4.s_addr == INADDR_ANY                   \
                  : (((prefix)->family == AF_INET6)                            \
                             ? (IN6_IS_ADDR_UNSPECIFIED(&(prefix)->u.prefix6)) \
                             : 0)))
index 762cd2596f853d74632038b3aacf844d738ed940..bc29f05aebe73ead11cb5af3aecdb6715b1230d4 100644 (file)
@@ -134,7 +134,7 @@ static void encap_attr_export_ce(struct attr *new, struct attr *orig,
 static int getce(struct bgp *bgp, struct attr *attr, struct prefix *pfx_ce)
 {
        uint8_t *ecp;
-       int i;
+       uint32_t i;
        uint16_t localadmin = bgp->rfapi_cfg->resolve_nve_roo_local_admin;
 
        for (ecp = attr->ecommunity->val, i = 0; i < attr->ecommunity->size;
index ea60b921d1b5c5888b078b3e98dabdf560172fd8..df1555c32a05afdf9d0099c873e61c0e55c9f776 100644 (file)
@@ -18,6 +18,7 @@ vtysh_scan += \
        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 \
@@ -95,6 +96,7 @@ bgpd_libbgp_a_SOURCES = \
        bgpd/bgp_regex.c \
        bgpd/bgp_route.c \
        bgpd/bgp_routemap.c \
+       bgpd/bgp_script.c \
        bgpd/bgp_table.c \
        bgpd/bgp_updgrp.c \
        bgpd/bgp_updgrp_adv.c \
@@ -174,6 +176,7 @@ noinst_HEADERS += \
        bgpd/bgp_rd.h \
        bgpd/bgp_regex.h \
        bgpd/bgp_route.h \
+       bgpd/bgp_script.h \
        bgpd/bgp_table.h \
        bgpd/bgp_updgrp.h \
        bgpd/bgp_vpn.h \
index 127d7fe1472c613659662edc8f916fc8520177f1..50bd5f6d4d4df369fbf961bab3dee7785f08ff65 100644 (file)
@@ -6,6 +6,73 @@ frr (@VERSION@-0) UNRELEASED; urgency=medium
 
  -- FRRouting-Dev <dev@lists.frrouting.org>  Thu, 25 Oct 2018 16:36:50 +0200
 
+frr (7.5-0) RELEASED; urgency=medium
+  BFD
+    Profile support
+    Minimum ttl support
+  BGP
+    rpki VRF support
+    GR fixes
+    Add wide option to display of routes
+    Add `maximum-prefix <num> force`
+    Add `bestpath-routes` to neighbor command
+    Add `bgp shutdown message MSG...` command
+    Add v6 Flowspec support
+    Add `neighbor <neigh> shutdown rtt` command
+    Allow update-delay to be applied globaly
+  EVPN
+    Beginning of MultiHoming Support
+  ISIS
+    Segment Routing Support
+    VRF Support
+    Guard against adj timer display overflow
+    Add support for Anycast-SIDs
+    Add support for Topology Independent LFA (TI-LFA)
+    Add `lsp-gen-interval 2` to isis configuration
+  OSPF
+    Segment Routing support for ECMP
+    Various LSA fixes
+    Prevent crash if transferring config amongst instances
+  PBR
+    Adding json support to commands
+    DSCP/ECN based PBR Matching
+  PIM
+    Add more json support to commands
+    Fix missing mesh-group commands
+    MSDP SA forwarding
+    Clear (s,g,rpt) ifchannel on (*, G) prune received
+    Fix igmp querier election and IP address mapping
+    Crash fix when RP is removed
+  STATIC
+    Northbound Support
+  YANG
+    Filter and route-map Support
+    OSPF model definition
+    BGP model definition
+  VTYSH
+    Speed up output across daemons
+    Fix build-time errors for some --enable flags
+    Speed up output of configuration across daemons
+  ZEBRA
+    nexthop group support for FPM
+    northbound support for rib model
+    Backup nexthop support
+    netlink batching support
+    Allow upper level protocols to request ARP
+    Add json output for zebra ES, ES-EVI and access vlan dumps
+
+  Upgrade to using libyang1.0.184
+
+  RPM
+    Moved RPKI to subpackage
+    Added SNMP subpackage
+
+  As always there are too many bugfixes to list individually.  This release
+  compromises just over 1k of commits by the community, with contributors from
+  70 people.
+
+ -- FRRouting-Dev <dev@lists.frrouting.org>  Tue, 2 Nov 2020 08:04:23 +0400
+
 frr (6.0-2) testing; urgency=medium
 
   * add install-info to build deps
index 237552c1408b0c2c380ea94e857f9b8b2bee445f..8f9517763d359d31ecec787fcbba27fd80a399fd 100755 (executable)
@@ -25,6 +25,13 @@ dnl -----------------------------------
 AC_CANONICAL_BUILD()
 AC_CANONICAL_HOST()
 
+AC_ARG_VAR([AR],[archiver command])
+AC_ARG_VAR([LD],[linker command])
+AC_ARG_VAR([OBJCOPY],[objcopy command])
+AC_ARG_VAR([OBJDUMP],[objdump command])
+AC_ARG_VAR([RANLIB],[ranlib command])
+AC_ARG_VAR([STRIP],[strip command])
+
 hosttools_clippy="false"
 build_clippy="true"
 
@@ -131,6 +138,12 @@ AC_ARG_WITH([moduledir], [AS_HELP_STRING([--with-moduledir=DIR], [module directo
 ])
 AC_SUBST([moduledir], [$moduledir])
 
+AC_ARG_WITH([scriptdir], [AS_HELP_STRING([--with-scriptdir=DIR], [script directory (${sysconfdir}/scripts)])], [
+       scriptdir="$withval"
+], [
+       scriptdir="\${sysconfdir}/scripts"
+])
+AC_SUBST([scriptdir], [$scriptdir])
 
 AC_ARG_WITH([yangmodelsdir], [AS_HELP_STRING([--with-yangmodelsdir=DIR], [yang models directory (${datarootdir}/yang)])], [
        yangmodelsdir="$withval"
@@ -267,24 +280,22 @@ if test "$enable_clang_coverage" = "yes"; then
    ])
 fi
 
+if test "$enable_scripting" = "yes"; then
+   AX_PROG_LUA([5.3])
+   AX_LUA_HEADERS
+   AX_LUA_LIBS([
+      AC_DEFINE([HAVE_SCRIPTING], [1], [Have support for scripting])
+      LIBS="$LIBS $LUA_LIB"
+   ])
+fi
+
 if test "$enable_dev_build" = "yes"; then
    AC_DEFINE([DEV_BUILD], [1], [Build for development])
    if test "$orig_cflags" = ""; then
       AC_C_FLAG([-g3])
       AC_C_FLAG([-O0])
    fi
-   if test "$enable_lua" = "yes"; then
-      AX_PROG_LUA([5.3])
-      AX_LUA_HEADERS
-      AX_LUA_LIBS([
-         AC_DEFINE([HAVE_LUA], [1], [Have support for Lua interpreter])
-         LIBS="$LIBS $LUA_LIB"
-      ])
-   fi
 else
-   if test "$enable_lua" = "yes"; then
-      AC_MSG_ERROR([Lua is not meant to be built/used outside of development at this time])
-   fi
    if test "$orig_cflags" = ""; then
       AC_C_FLAG([-g])
       AC_C_FLAG([-O2])
@@ -553,6 +564,8 @@ AC_ARG_ENABLE([fabricd],
   AS_HELP_STRING([--disable-fabricd], [do not build fabricd]))
 AC_ARG_ENABLE([vrrpd],
   AS_HELP_STRING([--disable-vrrpd], [do not build vrrpd]))
+AC_ARG_ENABLE([pathd],
+  AS_HELP_STRING([--disable-pathd], [do not build pathd]))
 AC_ARG_ENABLE([bgp-announce],
   AS_HELP_STRING([--disable-bgp-announce], [turn off BGP route announcement]))
 AC_ARG_ENABLE([bgp-vnc],
@@ -618,6 +631,8 @@ AC_ARG_ENABLE([pcreposix],
   AS_HELP_STRING([--enable-pcreposix], [enable using PCRE Posix libs for regex functions]))
 AC_ARG_ENABLE([fpm],
   AS_HELP_STRING([--enable-fpm], [enable Forwarding Plane Manager support]))
+AC_ARG_ENABLE([pcep],
+  AS_HELP_STRING([--enable-pcep], [enable PCEP support for pathd]))
 AC_ARG_ENABLE([systemd],
   AS_HELP_STRING([--enable-systemd], [enable Systemd support]))
 AC_ARG_ENABLE([werror],
@@ -686,8 +701,17 @@ fi
 AC_ARG_ENABLE([dev_build],
     AS_HELP_STRING([--enable-dev-build], [build for development]))
 
-AC_ARG_ENABLE([lua],
-    AS_HELP_STRING([--enable-lua], [Build Lua scripting]))
+AC_ARG_ENABLE([scripting],
+    AS_HELP_STRING([--enable-scripting], [Build with scripting support]))
+
+AC_ARG_ENABLE([netlink-debug],
+  AS_HELP_STRING([--disable-netlink-debug], [pretty print netlink debug messages]))
+
+if test "$enable_netlink_debug" != "no" ; then
+  AC_DEFINE([NETLINK_DEBUG], [1], [Netlink extra debugging code])
+fi
+
+AM_CONDITIONAL([NETLINK_DEBUG], [test "$enable_netlink_debug" != "no"])
 
 if test "$enable_time_check" != "no" ; then
   if test "$enable_time_check" = "yes" -o "$enable_time_check" = "" ; then
@@ -1659,6 +1683,14 @@ else
   esac
 fi
 
+AS_IF([test "$enable_pathd" != "no"], [
+  AC_DEFINE([HAVE_PATHD], [1], [pathd])
+])
+
+AS_IF([test "$enable_pcep" != "no"], [
+  AC_DEFINE([HAVE_PATHD_PCEP], [1], [pathd-pcep])
+])
+
 if test "$ac_cv_lib_json_c_json_object_get" = "no" -a "$BFDD" = "bfdd"; then
   AC_MSG_ERROR(["you must use json-c library to use bfdd"])
 fi
@@ -1834,7 +1866,7 @@ dnl ---------------
 dnl sysrepo
 dnl ---------------
 if test "$enable_sysrepo" = "yes"; then
-  PKG_CHECK_MODULES([SYSREPO], [libsysrepo],
+  PKG_CHECK_MODULES([SYSREPO], [sysrepo],
       [AC_DEFINE([HAVE_SYSREPO], [1], [Enable sysrepo integration])
       SYSREPO=true],
       [SYSREPO=false
@@ -2418,19 +2450,23 @@ CFG_SBIN="$sbindir"
 CFG_STATE="$frr_statedir"
 CFG_MODULE="$moduledir"
 CFG_YANGMODELS="$yangmodelsdir"
+CFG_SCRIPT="$scriptdir"
 for I in 1 2 3 4 5 6 7 8 9 10; do
        eval CFG_SYSCONF="\"$CFG_SYSCONF\""
        eval CFG_SBIN="\"$CFG_SBIN\""
        eval CFG_STATE="\"$CFG_STATE\""
        eval CFG_MODULE="\"$CFG_MODULE\""
        eval CFG_YANGMODELS="\"$CFG_YANGMODELS\""
+       eval CFG_SCRIPT="\"$CFG_SCRIPT\""
 done
 AC_SUBST([CFG_SYSCONF])
 AC_SUBST([CFG_SBIN])
 AC_SUBST([CFG_STATE])
 AC_SUBST([CFG_MODULE])
+AC_SUBST([CFG_SCRIPT])
 AC_SUBST([CFG_YANGMODELS])
 AC_DEFINE_UNQUOTED([MODULE_PATH], ["$CFG_MODULE"], [path to modules])
+AC_DEFINE_UNQUOTED([SCRIPT_PATH], ["$CFG_SCRIPT"], [path to scripts])
 AC_DEFINE_UNQUOTED([YANG_MODELS_PATH], ["$CFG_YANGMODELS"], [path to YANG data models])
 AC_DEFINE_UNQUOTED([WATCHFRR_SH_PATH], ["${CFG_SBIN%/}/watchfrr.sh"], [path to watchfrr.sh])
 
@@ -2451,6 +2487,18 @@ AM_CONDITIONAL([IRDP], [$IRDP])
 AM_CONDITIONAL([FPM], [test "$enable_fpm" = "yes"])
 AM_CONDITIONAL([HAVE_PROTOBUF], [test "$enable_protobuf" = "yes"])
 AM_CONDITIONAL([HAVE_PROTOBUF3], [$PROTO3])
+
+dnl PCEP plugin
+AM_CONDITIONAL([HAVE_PATHD_PCEP], [test "$enable_pcep" = "yes"])
+AS_IF([test "$enable_pcep" = "yes"], [
+  AC_CHECK_LIB([pcep_pcc], [initialize_pcc], [
+    PATHD_PCEP_LIBS="-lpcep_pcc"
+  ],[
+    AC_MSG_ERROR([PCEP library libpcep_pcc not found])
+  ])
+  AC_SUBST([PATHD_PCEP_LIBS])
+])
+
 dnl daemons
 AM_CONDITIONAL([VTYSH], [test "$VTYSH" = "vtysh"])
 AM_CONDITIONAL([ZEBRA], [test "$enable_zebra" != "no"])
@@ -2473,6 +2521,7 @@ AM_CONDITIONAL([SHARPD], [test "$enable_sharpd" = "yes"])
 AM_CONDITIONAL([STATICD], [test "$enable_staticd" != "no"])
 AM_CONDITIONAL([FABRICD], [test "$enable_fabricd" != "no"])
 AM_CONDITIONAL([VRRPD], [test "$enable_vrrpd" != "no"])
+AM_CONDITIONAL([PATHD], [test "$enable_pathd" != "no"])
 
 AC_CONFIG_FILES([Makefile],[
        test "$enable_dev_build" = "yes" && makefile_devbuild="--dev-build"
@@ -2500,19 +2549,6 @@ AC_CONFIG_FILES([tools/watchfrr.sh], [chmod +x tools/watchfrr.sh])
 AC_CONFIG_FILES([tools/frrinit.sh], [chmod +x tools/frrinit.sh])
 AC_CONFIG_FILES([tools/frrcommon.sh])
 
-AC_CONFIG_COMMANDS([lib/route_types.h], [
-       dst="${ac_abs_top_builddir}/lib/route_types.h"
-       ${PERL} "${ac_abs_top_srcdir}/lib/route_types.pl" \
-               < "${ac_abs_top_srcdir}/lib/route_types.txt" \
-               > "${dst}.tmp"
-       test -f "$dst" \
-               && diff "${dst}.tmp" "${dst}" >/dev/null 2>/dev/null \
-               && rm "${dst}.tmp" \
-               || mv "${dst}.tmp" "${dst}"
-], [
-       PERL="$PERL"
-])
-
 AS_IF([test "$with_pkg_git_version" = "yes"], [
     AC_CONFIG_COMMANDS([lib/gitversion.h], [
        dst="${ac_abs_top_builddir}/lib/gitversion.h"
@@ -2554,6 +2590,7 @@ state file directory    : ${frr_statedir}
 config file directory   : `eval echo \`echo ${sysconfdir}\``
 example directory       : `eval echo \`echo ${exampledir}\``
 module directory        : ${CFG_MODULE}
+script directory        : ${CFG_SCRIPT}
 user to run as          : ${enable_user}
 group to run as         : ${enable_group}
 group for vty sockets   : ${enable_vty_group}
index 4aaa9f21bf8884dd26717e56457757d678aabff4..b9e96b55d0eab385cda36f642b585f8ccefdb403 100644 (file)
@@ -29,7 +29,8 @@ Build-Depends: bison,
                python3-dev,
                python3-pytest <!nocheck>,
                python3-sphinx,
-               texinfo (>= 4.7)
+               texinfo (>= 4.7),
+               liblua5.3-dev <pkg.frr.lua>
 Standards-Version: 4.5.0.3
 Homepage: https://www.frrouting.org/
 Vcs-Browser: https://github.com/FRRouting/frr/tree/debian/master
index 6cc03c378ac4ae0b90c75e4b3a9ba2089d9ef0cf..25ae04261d3d1d400066d5749831eb152d9f154e 100755 (executable)
@@ -29,6 +29,12 @@ else
   CONF_SYSTEMD=--enable-systemd=no
 endif
 
+ifeq ($(filter pkg.frr.lua,$(DEB_BUILD_PROFILES)),)
+  CONF_LUA=--disable-scripting
+else
+  CONF_LUA=--enable-scripting
+endif
+
 export PYTHON=python3
 
 %:
@@ -49,6 +55,7 @@ override_dh_auto_configure:
                \
                $(CONF_SYSTEMD) \
                $(CONF_RPKI) \
+               $(CONF_LUA) \
                --with-libpam \
                --enable-doc \
                --enable-doc-html \
diff --git a/doc/developer/building-frr-for-opensuse.rst b/doc/developer/building-frr-for-opensuse.rst
new file mode 100644 (file)
index 0000000..5ed714a
--- /dev/null
@@ -0,0 +1,143 @@
+openSUSE
+========
+
+This document describes installation from source.
+
+These instructions have been tested on openSUSE Tumbleweed in a Raspberry Pi 400.
+
+Installing Dependencies
+-----------------------
+
+.. code-block:: console
+
+   zypper in  git autoconf automake libtool make   \
+     readline-devel texinfo net-snmp-devel groff pkgconfig libjson-c-devel\
+     pam-devel python3-pytest bison flex c-ares-devel python3-devel\
+     python3-Sphinx perl patch systemd-devel libcap-devel libyang-devel
+
+Building & Installing FRR
+-------------------------
+
+Add FRR user and groups
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+   sudo groupadd -g 92 frr
+   sudo groupadd -r -g 85 frrvty
+   sudo useradd -u 92 -g 92 -M -r -G frrvty -s /sbin/nologin \
+     -c "FRR FRRouting suite" -d /var/run/frr frr
+
+Compile
+^^^^^^^
+
+.. include:: include-compile.rst
+
+Install FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+   sudo install -m 775 -o frr -g frr -d /var/log/frr
+   sudo install -m 775 -o frr -g frrvty -d /etc/frr
+   sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
+
+.. note::
+
+        In some platforms like raspberry for performance reasons
+        some directories are in file systems (/var/run, ...) mounted with tempfs 
+        so will disapear after every reboot.
+        In frr the /var/run/frr is used to store pid files for every daemon.
+
+Tweak sysctls
+^^^^^^^^^^^^^
+
+Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
+MPLS (if supported by your platform). If your platform does not support MPLS,
+skip the MPLS related configuration in this section.
+
+Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the following
+content:
+
+::
+
+   #
+   # Enable packet forwarding
+   #
+   net.ipv4.conf.all.forwarding=1
+   net.ipv6.conf.all.forwarding=1
+   #
+   # Enable MPLS Label processing on all interfaces
+   #
+   #net.mpls.conf.eth0.input=1
+   #net.mpls.conf.eth1.input=1
+   #net.mpls.conf.eth2.input=1
+   #net.mpls.platform_labels=100000
+
+.. note::
+
+   MPLS must be invidividually enabled on each interface that requires it. See
+   the example in the config block above.
+
+Load the modifed sysctls on the system:
+
+.. code-block:: console
+
+   sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
+
+Create a new file ``/etc/modules-load.d/mpls.conf`` with the following content:
+
+::
+
+   # Load MPLS Kernel Modules
+   mpls-router
+   mpls-iptunnel
+
+And load the kernel modules on the running system:
+
+.. code-block:: console
+
+   sudo modprobe mpls-router mpls-iptunnel
+
+
+.. note::
+   The ``firewalld`` service could be enabled. You may run into some
+   issues with the iptables rules it installs by default. If you wish to just
+   stop the service and clear `ALL` rules do these commands:
+
+   .. code-block:: console
+
+      sudo systemctl disable firewalld.service
+      sudo systemctl stop firewalld.service
+      sudo iptables -F
+
+Install frr Service
+^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+   sudo install -p -m 644 tools/frr.service /usr/lib/systemd/system/frr.service
+   sudo systemctl enable frr
+
+Enable daemons
+^^^^^^^^^^^^^^
+
+Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
+section with ``bgpd=no`` etc.  Enable the daemons
+as required by changing the value to ``yes``.
+
+Start FRR
+^^^^^^^^^
+
+.. code-block:: console
+
+   sudo systemctl start frr
+
+Check the starting messages of frr with
+
+.. code-block:: console
+
+   journalctl -u frr --follow
index 730741a8efc03c397d4e7a1192968d0dfe794014..a6cd545872f0fefe3d151d16e2c702c09937ae2a 100644 (file)
@@ -15,6 +15,7 @@ Building FRR
    building-frr-for-debian8
    building-frr-for-debian9
    building-frr-for-fedora
+   building-frr-for-opensuse
    building-frr-for-freebsd10
    building-frr-for-freebsd11
    building-frr-for-freebsd9
index ff95aa04a9d1623f2eaac820c60e1c641979f8cd..5da73f61f6c99d5e64762fe8d25ef580336fb066 100644 (file)
@@ -20,7 +20,13 @@ FRR Release Procedure
       git checkout -b stable/<version>
       git push origin stable/<version>:refs/heads/stable/<version>
 
-3. Update Changelog for Red Hat Packages:
+3. Remove the development branch called ``dev/<version>``
+
+   .. code-block:: console
+
+      git push origin --delete dev/<version>
+
+4. Update Changelog for Red Hat Packages:
 
    Edit :file:`redhat/frr.spec.in` and look for the ``%changelog`` section:
 
@@ -41,7 +47,7 @@ FRR Release Procedure
 
    - Add the changelog text below this entry.
 
-4. Update Changelog for Debian Packages:
+5. Update Changelog for Debian Packages:
 
    Edit :file:`changelog-auto.in`:
 
@@ -83,41 +89,41 @@ FRR Release Procedure
          .
            * Your Changes Here
 
-5. Change main version number:
+6. Change main version number:
 
     - Edit :file:`configure.ac` and change version in the ``AC_INIT`` command
       to ``<version>``
 
-6. Commit the changes, adding the changelog to the commit message. Follow all
+7. Commit the changes, adding the changelog to the commit message. Follow all
    existing commit guidelines.
 
-7. Create and submit a GitHub pull request, with the ``HEAD`` set to
+8. Create and submit a GitHub pull request, with the ``HEAD`` set to
    ``stable/<version>`` and the base set to the upstream ``master`` branch.
    Allow NetDef CI to complete its run and verify that all package builds were
    successful.
 
-8. Create a git tag for the version:
+9. Create a git tag for the version:
 
    .. code-block:: console
 
       git tag -a frr-<version> -m "FRRouting Release <version>"
 
-9. Push the commit and new tag.
+10. Push the commit and new tag.
 
    .. code-block:: console
 
       git push origin stable/<version>:refs/head/stable/<version>
       git push origin frr-<version>
 
-10. Kick off the Release build plan on the CI system for the correct release.
+11. Kick off the Release build plan on the CI system for the correct release.
     Contact Martin Winter for this step. Ensure all release packages build
     successfully.
 
-11. Kick off the Snapcraft build plan for the release.
+12. Kick off the Snapcraft build plan for the release.
 
-12. Acquire the release RPM binary packages from Martin Winter.
+13. Acquire the release RPM binary packages from Martin Winter.
 
-13. On GitHub, go to the <https://github.com/FRRouting/frr/releases>_ and click
+14. On GitHub, go to the <https://github.com/FRRouting/frr/releases>_ and click
     "Draft a new release". Write a release announcement. The release
     announcement should follow the template in
     ``release-announcement-template.md``, located next to this document. Check
@@ -129,27 +135,27 @@ FRR Release Procedure
     attach source tarballs - these will be generated and attached by GitHub
     automatically. Do not publish the release yet.
 
-14. Contact the current Debian maintainer for FRR to get new Debian packages
+15. Contact the current Debian maintainer for FRR to get new Debian packages
     built and published on our APT repository at https://deb.frrouting.net/.
     Ensure the webpage text is updated. Verify that new packages install
     successfully on a vanilla Debian installation using the instructions on the
     webpage.
 
-15. Deploy Snapcraft release (after CI system finishes the tests for snapcraft
+16. Deploy Snapcraft release (after CI system finishes the tests for snapcraft
     testplan).
 
-16. Update the Read The Docs instance to being publishing documentation built
+17. Update the Read The Docs instance to being publishing documentation built
     off the ``stable/<version>`` branch. Contact Quentin Young for this step.
 
-17. Publish the GitHub release.
+18. Publish the GitHub release.
 
-18. Clone the ``frr-www`` repository:
+19. Clone the ``frr-www`` repository:
 
     .. code-block:: console
 
        git clone https://github.com/FRRouting/frr-www.git
 
-19. Add a new release announcement, using a previous announcement as template:
+20. Add a new release announcement, using a previous announcement as template:
 
     .. code-block:: console
 
@@ -174,8 +180,13 @@ FRR Release Procedure
     Once finished, manually add a new entry into ``index.html`` to link to this
     new announcement. Look at past commits to see how to do this.
 
-20. Deploy the updated ``frr-www`` on the frrouting.org web server and verify
+21. Deploy the updated ``frr-www`` on the frrouting.org web server and verify
     that the announcement text is visible.
 
-21. Send an email to ``announce@lists.frrouting.org``. The text of this email
+22. Send an email to ``announce@lists.frrouting.org``. The text of this email
     should include the text from the GitHub release.
+
+23. Update masters version of the changelog-auto.in
+
+    Take the change data and cut-n-paste the changes into the master version below
+    the @VERSION@-0 lines.  So we have the history of the previous release.
index 5a7da806ffb1aa0f2f5e0627fec9d4c80e7c2442..8e7913419f2d982c77b1d7cfbe149da69fe58777 100644 (file)
@@ -18,3 +18,5 @@ FRRouting Developer's Guide
    ospf
    zebra
    vtysh
+   path
+   link-state
index 3d5c6a2a15d444930f1c9477bbd4ce86c6ec35c7..1bfe5df2f095b1611c1a7a74aaa40fc0d57103a9 100644 (file)
@@ -15,6 +15,6 @@ Library Facilities (libfrr)
    hooks
    cli
    modules
-   lua
+   scripting
 
 
diff --git a/doc/developer/link-state.rst b/doc/developer/link-state.rst
new file mode 100644 (file)
index 0000000..f1fc529
--- /dev/null
@@ -0,0 +1,314 @@
+Link State API Documentation
+============================
+
+Introduction
+------------
+
+The Link State (LS) API aims to provide a set of structures and functions to
+build and manage a Traffic Engineering Database for the various FRR daemons.
+This API has been designed for several use cases:
+
+- BGP Link State (BGP-LS): where BGP protocol need to collect the link state
+  information from the routing daemons (IS-IS and/or OSPF) to implement RFC7572
+- Path Computation Element (PCE): where path computation algorithms are based
+  on Traffic Engineering Database
+- ReSerVation Protocol (RSVP): where signaling need to know the Traffic
+  Engineering topology of the network in order to determine the path of
+  RSVP tunnels
+
+Architecture
+------------
+
+The main requirements from the various uses cases are as follow:
+
+- Provides a set of data model and function to ease Link State information
+  manipulation (storage, serialize, parse ...)
+- Ease and normalize Link State information exchange between FRR daemons
+- Provides database structure for Traffic Engineering Database (TED)
+
+To ease Link State understanding, FRR daemons have been classified into two
+categories:
+
+- **Consumer**: Daemons that consume Link State information e.g. BGPd
+- **Producer**: Daemons that are able to collect Link State information and
+  send them to consumer daemons e.g. OSPFd IS-ISd
+
+Zebra daemon, and more precisely, the ZAPI message is used to convey the Link
+State information between *producer* and *consumer*, but, Zebra acts as a
+simple pass through and does not store any Link State information. A new ZAPI
+**Opaque** message has been design for that purpose.
+
+Each consumer and producer daemons are free to store or not Link State data and
+organise the information following the Traffic Engineering Database model
+provided by the API or any other data structure e.g. Hash, RB-tree ...
+
+Link State API
+--------------
+
+This is the low level API that allows any daemons manipulate the Link State
+elements that are stored in the Link State Database.
+
+Data structures
+^^^^^^^^^^^^^^^
+
+3 types of Link State structure have been defined:
+
+.. c:type:: struct ls_node
+
+   that groups all information related to a node
+
+.. c:type:: struct ls_attributes
+
+   that groups all information related to a link
+
+.. c:type:: struct ls_prefix
+
+   that groups all information related to a prefix
+
+These 3 types of structures are those handled by BGP-LS (see RFC7752) and
+suitable to describe a Traffic Engineering topology.
+
+Each structure, in addition to the specific parameters, embed the node
+identifier which advertises the Link State and a bit mask as flags to
+indicates which parameters are valid i.e. for which the value is valid and
+corresponds to a Link State information conveyed by the routing protocol.
+
+.. c:type:: struct ls_node_id
+
+   defines the Node identifier as router ID IPv4 address plus the area ID for
+   OSPF or the ISO System ID plus the IS-IS level for IS-IS.
+
+Functions
+^^^^^^^^^
+
+A set of functions is provided to create, delete and compare Link State Node:
+
+.. c:function:: struct ls_node *ls_node_new(struct ls_node_id adv, struct in_addr router_id, struct in6_addr router6_id)
+.. c:function:: voidls_node_del(struct ls_node *node)
+.. c:function:: int ls_node_same(struct ls_node *n1, struct ls_node *n2)
+
+and Link State Attributes:
+
+.. c:function:: struct ls_attributes *ls_attributes_new(struct ls_node_id adv, struct in_addr local, struct in6_addr local6, uint32_t local_id)
+.. c:function:: void ls_attributes_del(struct ls_attributes *attr)
+.. c:function:: int ls_attributes_same(struct ls_attributes *a1, struct ls_attributes *a2)
+
+The low level API doesn't provide any particular functions for the Link State
+Prefix structure as this latter is simpler to manipulate.
+
+Link State TED
+--------------
+
+This is the high level API that provides functions to create, update, delete a
+Link State Database to from a Traffic Engineering Database (TED).
+
+Data Structures
+^^^^^^^^^^^^^^^
+
+The Traffic Engineering is modeled as a Graph in order to ease Path Computation
+algorithm implementation. Denoted **G(V, E)**, a graph is composed by a list of
+**Vertices (V)** which represents the network Node and a list of **Edges (E)**
+which represents Link. An additional list of **prefixes (P)** is also added and
+also attached to the *Vertex (V)* which advertise it.
+
+*Vertex (V)* contains the list of outgoing *Edges (E)* that connect this Vertex
+with its direct neighbors and the list of incoming *Edges (E)* that connect
+the direct neighbors to this Vertex. Indeed, the *Edge (E)* is unidirectional,
+thus, it is necessary to add 2 Edges to model a bidirectional relation between
+2 Vertices. Finally, the *Vertex (V)* contains a pointer to the corresponding
+Link State Node.
+
+*Edge (E)* contains the source and destination Vertex that this Edge
+is connecting and a pointer to the corresponding Link State Attributes.
+
+A unique Key is used to identify both Vertices and Edges within the Graph.
+
+
+::
+
+          --------------     ---------------------------    --------------
+          | Connected  |---->| Connected Edge Va to Vb |--->| Connected  |
+      --->|  Vertex    |     ---------------------------    |  Vertex    |---->
+          |            |                                    |            |
+          | - Key (Va) |                                    | - Key (Vb) |
+      <---| - Vertex   |     ---------------------------    | - Vertex   |<----
+          |            |<----| Connected Edge Vb to Va |<---|            |
+          --------------     ---------------------------    --------------
+
+
+4 data structures have been defined to implement the Graph model:
+
+.. c:type:: struct ls_vertex
+.. c:type:: struct ls_edge
+.. c:type:: struct ls_prefix
+.. c:type:: struct ls_ted
+
+
+Functions
+^^^^^^^^^
+
+.. c:function:: struct ls_vertex *ls_vertex_add(struct ls_ted *ted, struct ls_node *node)
+.. c:function:: struct ls_vertex *ls_vertex_update(struct ls_ted *ted, struct ls_node *node)
+.. c:function:: void ls_vertex_del(struct ls_ted *ted, struct ls_vertex *vertex)
+.. c:function:: struct ls_vertex *ls_find_vertex_by_key(struct ls_ted *ted, const uint64_t key)
+.. c:function:: struct ls_vertex *ls_find_vertex_by_id(struct ls_ted *ted, struct ls_node_id id)
+.. c:function:: int ls_vertex_same(struct ls_vertex *v1, struct ls_vertex *v2)
+
+.. c:function:: struct ls_edge *ls_edge_add(struct ls_ted *ted, struct ls_attributes *attributes)
+.. c:function:: struct ls_edge *ls_edge_update(struct ls_ted *ted, struct ls_attributes *attributes)
+.. c:function:: void ls_edge_del(struct ls_ted *ted, struct ls_edge *edge)
+.. c:function:: struct ls_edge *ls_find_edge_by_key(struct ls_ted *ted, const uint64_t key)
+.. c:function:: struct ls_edge *ls_find_edge_by_source(struct ls_ted *ted, struct ls_attributes *attributes);
+.. c:function:: struct ls_edge *ls_find_edge_by_destination(struct ls_ted *ted, struct ls_attributes *attributes);
+
+.. c:function:: struct ls_subnet *ls_subnet_add(struct ls_ted *ted, struct ls_prefix *pref)
+.. c:function:: void ls_subnet_del(struct ls_ted *ted, struct ls_subnet *subnet)
+.. c:function:: struct ls_subnet *ls_find_subnet(struct ls_ted *ted, const struct prefix prefix)
+
+.. c:function:: struct ls_ted *ls_ted_new(const uint32_t key, char *name, uint32_t asn)
+.. c:function:: void ls_ted_del(struct ls_ted *ted)
+.. c:function:: void ls_connect_vertices(struct ls_vertex *src, struct ls_vertex *dst, struct ls_edge *edge)
+.. c:function:: void ls_connect(struct ls_vertex *vertex, struct ls_edge *edge, bool source)
+.. c:function:: void ls_disconnect(struct ls_vertex *vertex, struct ls_edge *edge, bool source)
+.. c:function:: void ls_disconnect_edge(struct ls_edge *edge)
+
+
+Link State Messages
+-------------------
+
+This part of the API provides functions and data structure to ease the
+communication between the *Producer* and *Consumer* daemons.
+
+Communications principles
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Recent ZAPI Opaque Message is used to exchange Link State data between daemons.
+For that purpose, Link State API provides new functions to serialize and parse
+Link State information through the ZAPI Opaque message. A dedicated flag,
+named ZAPI_OPAQUE_FLAG_UNICAST, allows daemons to send a unicast or a multicast
+Opaque message and is used as follow for the Link State exchange:
+
+- Multicast: To send data update to all daemons that have subscribed to the
+  Link State Update message
+- Unicast: To send initial Link State information from a particular daemon. All
+  data are send only to the daemon that request Link State Synchronisatio
+
+Figure 1 below, illustrates the ZAPI Opaque message exchange between a
+*Producer* (an IGP like OSPF or IS-IS) and a *Consumer* (e.g. BGP). The
+message sequences are as follows:
+
+- First, both *Producer* and *Consumer* must register to their respective ZAPI
+  Opaque Message. **Link State Sync** for the *Producer* in order to receive
+  Database synchronisation request from a *Consumer*. **Link State Update** for
+  the *Consumer* in order to received any Link State update from a *Producer*.
+  These register messages are stored by Zebra to determine to which daemon it
+  should redistribute the ZAPI messages it receives.
+- Then, the *Consumer* sends a **Link State Synchronistation** request with the
+  Multicast method in order to receive the complete Link State Database from a
+  *Producer*. ZEBRA daemon forwards this message to any *Producer* daemons that
+  previously registered to this message. If no *Producer* has yet registered,
+  the request is lost. Thus, if the *Consumer* receives no response whithin a
+  given timer, it means that no *Producer* are available right now. So, the
+  *Consumer* must send the same request until it receives a Link State Database
+  Synchronistation message. This behaviour is necessary as we can't control in
+  which order daemons are started. It is up to the *Consumer* daemon to fix the
+  timeout and the number of retry.
+- When a *Producer* receives a **Link State Synchronisation** request, it
+  starts sending all elements of its own Link State Database through the
+  **Link State Database Synchronisation** message. These messages are send with
+  the Unicast method to avoid flooding other daemons with these elements. ZEBRA
+  layer ensures to forward the message to the right daemon.
+- When a *Producer* update its Link State Database, it automatically sends a
+  **Link State Update** message with the Multicast method. In turn, ZEBRA
+  daemon forwards the message to all *Consumer* daemons that previously
+  registered to this message. if no daemon is registered, the message is lost.
+- A daemon could unregister from the ZAPI Opaque message registry at any time.
+  In this case, the ZEBRA daemon stops to forward any messages it receives to
+  this daemon, even if it was previously converns.
+
+::
+
+       IGP                           ZEBRA                        Consumer
+    (OSPF/IS-IS)               (ZAPI Opaque Thread)              (e.g. BGP)
+        |                              |                             |           \
+        |                              |      Register LS Update     |            |
+        |                              |<----------------------------|   Register Phase
+        |                              |                             |            |
+        |                              |      Request LS Sync        |            |
+        |                              |<----------------------------|            |
+        :                              :                             :  A         |
+        |    Register LS Sync          |                             |  |         |
+        |----------------------------->|                             |  |        /
+        :                              :                             :  |TimeOut
+        :                              :                             :  |
+        |                              |                             |  |
+        |                              |      Request LS Sync        |  v        \
+        |    Request LS Sync           |<----------------------------|            |
+        |<-----------------------------|                             |   Synchronistation
+        |    LS DB Sync                |                             |           Phase
+        |----------------------------->|      LS DB Sync             |            |
+        |                              |---------------------------->|            |
+        |    LS DB Sync (cont'd)       |                             |            |
+        |----------------------------->|      LS DB Sync (cont'd)    |            |
+        |            .                 |---------------------------->|            |
+        |            .                 |             .               |            |
+        |            .                 |             .               |            |
+        |    LS DB Sync (end)          |             .               |            |
+        |----------------------------->|      LS DB Sync (end)       |            |
+        |                              |---------------------------->|            |
+        |                              |                             |           /
+        :                              :                             :
+        :                              :                             :
+        |    LS Update                 |                             |           \
+        |----------------------------->|      LS Update              |            |
+        |                              |---------------------------->|      Update Phase
+        |                              |                             |            |
+        :                              :                             :           /
+        :                              :                             :
+        |                              |                             |           \
+        |                              |      Unregister LS Update   |            |
+        |                              |<----------------------------|      Deregister Phase
+        |                              |                             |            |
+        |    LS Update                 |                             |            |
+        |----------------------------->|                             |            |
+        |                              |                             |           /
+        |                              |                             |
+
+        Figure 1: Link State messages exchange
+
+
+Data Structures
+^^^^^^^^^^^^^^^
+
+The Link State Message is defined to convey Link State parameters from
+the routing protocol (OSPF or IS-IS) to other daemons e.g. BGP.
+
+.. c:type:: struct ls_message
+
+The structure is composed of:
+
+- Event of the message:
+
+  - Sync: Send the whole LS DB following a request
+  - Add: Send the a new Link State element
+  - Update: Send an update of an existing Link State element
+  - Delete: Indicate that the given Link State element is removed
+
+- Type of Link State element: Node, Attribute or Prefix
+- Remote node id when known
+- Data: Node, Attributes or Prefix
+
+A Link State Message can carry only one Link State Element (Node, Attributes
+of Prefix) at once, and only one Link State Message is sent through ZAPI
+Opaque Link State type at once.
+
+Functions
+^^^^^^^^^
+
+.. c:function:: struct ls_message *ls_parse_msg(struct stream *s)
+.. c:function:: int ls_send_msg(struct zclient *zclient, struct ls_message *msg, struct zapi_opaque_reg_info *dst)
+.. c:function:: struct ls_message *ls_vertex2msg(struct ls_message *msg, struct ls_vertex *vertex)
+.. c:function:: struct ls_message *ls_edge2msg(struct ls_message *msg, struct ls_edge *edge)
+.. c:function:: struct ls_message *ls_subnet2msg(struct ls_message *msg, struct ls_subnet *subnet)
+.. c:function:: int ls_sync_ted(struct ls_ted *ted, struct zclient *zclient, struct zapi_opaque_reg_info *dst)
+
index 2f2444373c842d23378bdeccae0493a771a0812e..cf3aa8d17f0741cee84eb3a8fc3813b26f130c04 100644 (file)
@@ -83,7 +83,7 @@ Extensions
 +-----------+--------------------------+----------------------------------------------+
 | ``%pNHs`` | ``struct nexthop *``     | ``1.2.3.4 if 15``                            |
 +-----------+--------------------------+----------------------------------------------+
-| ``%pFX``  + ``struct bgp_dest *``    | ``fe80::1234/64`` available in BGP only      |
+| ``%pFX``  | ``struct bgp_dest *``    | ``fe80::1234/64`` (available in BGP only)    |
 +-----------+--------------------------+----------------------------------------------+
 
 Printf features like field lengths can be used normally with these extensions,
diff --git a/doc/developer/lua.rst b/doc/developer/lua.rst
deleted file mode 100644 (file)
index 3315c31..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-.. _lua:
-
-Lua
-===
-
-Lua is currently experimental within FRR and has very limited
-support.  If you would like to compile FRR with Lua you must
-follow these steps:
-
-1. Installation of Relevant Libraries
-
-   .. code-block:: shell
-
-      apt-get install lua5.3 liblua5-3 liblua5.3-dev
-
-   These are the Debian libraries that are needed.  There should
-   be equivalent RPM's that can be found
-
-2. Compilation
-
-   Configure needs these options
-
-   .. code-block:: shell
-
-      ./configure --enable-dev-build --enable-lua <all other interesting options>
-
-   Typically you just include the two new enable lines to build with it.
-
-3. Using Lua
-
-   * Copy tools/lua.scr into /etc/frr
-
-   * Create a route-map match command
-
-   .. code-block:: console
-
-      !
-      router bgp 55
-        neighbor 10.50.11.116 remote-as external
-          address-family ipv4 unicast
-            neighbor 10.50.11.116 route-map TEST in
-          exit-address-family
-      !
-      route-map TEST permit 10
-        match command mooey
-      !
-
-   * In the lua.scr file make sure that you have a function named 'mooey'
-
-   .. code-block:: console
-
-      function mooey ()
-         zlog_debug(string.format("afi: %d: %s %d ifdx: %d aspath: %s localpref: %d",
-                    prefix.family, prefix.route, nexthop.metric,
-                    nexthop.ifindex, nexthop.aspath, nexthop.localpref))
-
-         nexthop.metric =  33
-         nexthop.localpref = 13
-         return 3
-      end
-
-4. General Comments
-
-   Please be aware that this is extremely experimental and needs a ton of work
-   to get this up into a state that is usable.
index e04049001d9e569098c364c4ef509602f33ad47e..952b316ea0b208392207b8db1aec6cf7050363bd 100644 (file)
@@ -131,3 +131,10 @@ Usage
    - if ptr is NULL, no operation is performed (as is guaranteed by system
      implementations.)  Do not surround XFREE with ``if (ptr != NULL)``
      checks.
+
+.. c:function:: void XCOUNTFREE(struct memtype *mtype, void *ptr)
+
+   This macro is used to count the ``ptr`` as freed without actually freeing
+   it. This may be needed in some very specific cases, for example, when the
+   ``ptr`` was allocated using any of the above wrappers and will be freed
+   by some external library using simple ``free()``.
diff --git a/doc/developer/path-internals-daemon.rst b/doc/developer/path-internals-daemon.rst
new file mode 100644 (file)
index 0000000..29f0172
--- /dev/null
@@ -0,0 +1,115 @@
+PATHD Internals
+===============
+
+Architecture
+------------
+
+Overview
+........
+
+The pathd deamon manages the segment routing policies, it owns the data
+structures representing them and can load modules that manipulate them like the
+PCEP module. Its responsibility is to select a candidate path for each
+configured policy and to install it into Zebra.
+
+Zebra
+.....
+
+Zebra manages policies that are active or pending to be activated due to the
+next hop not being available yet. In zebra, policy data structures and APIs are
+defined in `zebra_srte.[hc]`.
+
+The responsibilities of Zebra are:
+
+ - Store the policies' segment list.
+ - Install the policies when their next-hop is available.
+ - Notify other daemons of the status of the policies.
+
+Adding and removing policies is done using the commands `ZEBRA_SR_POLICY_SET`
+and `ZEBRA_SR_POLICY_DELETE` as parameter of the function `zebra_send_sr_policy`
+all defined in `zclient.[hc]`.
+
+If the first segment of the policy is an unknown label, it is kept until
+notified by the mpls hooks `zebra_mpls_label_created`, and then it is installed.
+
+To get notified when a policy status changes, a client can implement the
+`sr_policy_notify_status` callback defined in `zclient.[hc]`.
+
+For encoding/decoding the various data structures used to comunicate with zebra,
+the following functions are available from `zclient.[hc]`:
+`zapi_sr_policy_encode`, `zapi_sr_policy_decode` and
+`zapi_sr_policy_notify_status_decode`.
+
+
+Pathd
+.....
+
+
+The pathd daemon manages all the possible candidate paths for the segment
+routing policies and selects the best one following the
+`segment routing policy draft <https://tools.ietf.org/html/draft-ietf-spring-segment-routing-policy-06#section-2.9>`_.
+It also supports loadable modules for handling dynamic candidate paths and the
+creation of new policies and candidate paths at runtime.
+
+The responsibilities of the pathd base daemon, not including any optional
+modules, are:
+
+ - Store the policies and all the possible candidate paths for them.
+ - Select the best candidate path for each policy and send it to Zebra.
+ - Provide VTYSH configuration to set up policies and candidate paths.
+ - Provide a Northbound API to manipulate **configured** policies and candidate paths.
+ - Handle loadable modules for extending the functionality.
+ - Provide an API to the loadable module to manipulate policies and candidate paths.
+
+
+Threading Model
+---------------
+
+The daemon runs completely inside the main thread using FRR event model, there
+is no threading involved.
+
+
+Source Code
+-----------
+
+Internal Data Structures
+........................
+
+The main data structures for policies and candidate paths are defined in
+`pathd.h` and implemented in `pathd.c`.
+
+When modifying these structures, either directly or through the functions
+exported by `pathd.h`, nothing should be deleted/freed right away. The deletion
+or modification flags must be set and when all the changes are done, the
+function `srte_apply_changes` must be called. When called, a new candidate path
+may be elected and sent to Zebra, and all the structures flagged as deleted
+will be freed. In addition, a hook will be called so dynamic modules can perform
+any required action when the elected candidate path changes.
+
+
+Northbound API
+..............
+
+The northbound API is defined in `path_nb.[ch]` and implemented in
+`path_nb_config.c` for configuration data and `path_nb_state.c` for operational
+data.
+
+
+Command Line Client
+...................
+
+The command-line client (VTYSH) is implemented in `path_cli.c`.
+
+
+Interface with Zebra
+....................
+
+All the functions interfacing with Zebra are defined and implemented in
+`path_zebra.[hc]`.
+
+
+Loadable Module API
+...................
+
+For the time being, the API the loadable module uses is defined by `pathd.h`,
+but in the future, it should be moved to a dedicated include file.
diff --git a/doc/developer/path-internals-pcep.rst b/doc/developer/path-internals-pcep.rst
new file mode 100644 (file)
index 0000000..ca31831
--- /dev/null
@@ -0,0 +1,193 @@
+PCEP Module Internals
+=====================
+
+Introduction
+------------
+
+The PCEP module for the pathd daemon implements the PCEP protocol described in
+:rfc:`5440` to update the policies and candidate paths.
+
+The protocol encoding/decoding and the basic session management is handled by
+the `pceplib external library 1.2 <https://github.com/volta-networks/pceplib/tree/devel-1.2>`_.
+
+Together with pceplib, this module supports at least partially:
+
+  - :rfc:`5440`
+
+        Most of the protocol defined in the RFC is implemented.
+        All the messages can be parsed, but this was only tested in the context
+        of segment routing. Only a very small subset of metric types can be
+        configured, and there is a known issue with some Cisco routers not
+        following the IANA numbers for metrics.
+
+  - :rfc:`8231`
+
+        Support delegation of candidate path after performing the initial
+        computation request. If the PCE does not respond or cannot compute
+        a path, an empty candidate path is delegated to the PCE.
+        Only tested in the context of segment routing.
+
+  - :rfc:`8408`
+
+        Only used to comunicate the support for segment routing to the PCE.
+
+  - :rfc:`8664`
+
+        All the NAI types are implemented, but only the MPLS NAI are supported.
+        If the PCE provide segments that are not MPLS labels, the PCC will
+        return an error.
+
+Note that pceplib supports more RFCs and drafts, see pceplib
+`README <https://github.com/volta-networks/pceplib/blob/master/README.md>`_
+for more details.
+
+
+Architecture
+------------
+
+Overview
+........
+
+The module is separated into multiple layers:
+
+ - pathd interface
+ - command-line console
+ - controller
+ - PCC
+ - pceplib interface
+
+The pathd interface handles all the interactions with the daemon API.
+
+The command-line console handles all the VTYSH configuration commands.
+
+The controller manages the multiple PCC connections and the interaction between
+them and the daemon interface.
+
+The PCC handles a single connection to a PCE through a pceplib session.
+
+The pceplib interface abstracts the API of the pceplib.
+
+.. figure:: ../figures/pcep_module_threading_overview.svg
+
+
+Threading Model
+---------------
+
+The module requires multiple threads to cooperate:
+
+ - The main thread used by the pathd daemon.
+ - The controller pthread used to isolate the PCC from the main thread.
+ - The possible threads started in the pceplib library.
+
+To ensure thread safety, all the controller and PCC state data structures can
+only be read and modified in the controller thread, and all the global data
+structures can only be read and modified in the main thread. Most of the
+interactions between these threads are done through FRR timers and events.
+
+The controller is the bridge between the two threads, all the functions that
+**MUST** be called from the main thread start with the prefix `pcep_ctrl_` and
+all the functions that **MUST** be called from the controller thread start
+with the prefix `pcep_thread_`. When an asynchronous action must be taken in
+a different thread, an FRR event is sent to the thread. If some synchronous
+operation is needed, the calling thread will block and run a callback in the
+other thread, there the result is **COPIED** and returned to the calling thread.
+
+No function other than the controller functions defined for it should be called
+from the main thread. The only exception being some utility functions from
+`path_pcep_lib.[hc]`.
+
+All the calls to pathd API functions **MUST** be performed in the main thread,
+for that, the controller sends FRR events handled in function
+`path_pcep.c:pcep_main_event_handler`.
+
+For the same reason, the console client only runs in the main thread. It can
+freely use the global variable, but **MUST** use controller's `pcep_ctrl_`
+functions to interact with the PCCs.
+
+
+Source Code
+-----------
+
+Generic Data Structures
+.......................
+
+The data structures are defined in multiple places, and where they are defined
+dictates where they can be used.
+
+The data structures defined in `path_pcep.h` can be used anywhere in the module.
+
+Internally, throughout the module, the `struct path` data structure is used
+to describe PCEP messages. It is a simplified flattened structure that can
+represent multiple complex PCEP message types. The conversion from this
+structure to the PCEP data structures used by pceplib is done in the pceplib
+interface layer.
+
+The data structures defined in `path_pcep_controller.h` should only be used
+in `path_pcep_controller.c`. Even if a structure pointer is passed as a parameter
+to functions defined in `path_pcep_pcc.h`, these should consider it as an opaque
+data structure only used to call back controller functions.
+
+The same applies to the structures defined in `path_pcep_pcc.h`, even if the
+controller owns a reference to this data structure, it should never read or
+modify it directly, it should be considered an opaque structure.
+
+The global data structure can be accessed from the pathd interface layer
+`path_pcep.c` and the command line client code `path_pcep_cli.c`.
+
+
+Interface With Pathd
+....................
+
+All the functions calling or called by the pathd daemon are implemented in
+`path_pcep.c`. These functions **MUST** run in the main FRR thread, and
+all the interactions with the controller and the PCCs **MUST** pass through
+the controller's `pcep_ctrl_` prefixed functions.
+
+To handle asynchronous events from the PCCs, a callback is passed to
+`pcep_ctrl_initialize` that is called in the FRR main thread context.
+
+
+Command Line Client
+...................
+
+All the command line configuration commands (VTYSH) are implemented in
+`path_pcep_cli.c`. All the functions there run in the main FRR thread and
+can freely access the global variables. All the interaction with the
+controller's and the PCCs **MUST** pass through the controller `pcep_ctrl_`
+prefixed functions.
+
+
+Debugging Helpers
+.................
+
+All the functions formating data structures for debugging and logging purposes
+are implemented in `path_pcep_debug.[hc]`.
+
+
+Interface with pceplib
+......................
+
+All the functions calling the pceplib external library are defined in
+`path_pcep_lib.[hc]`. Some functions are called from the main FRR thread, like
+`pcep_lib_initialize`, `pcep_lib_finalize`; some can be called from either
+thread, like `pcep_lib_free_counters`; some function must be called from the
+controller thread, like `pcep_lib_connect`. This will probably be formalized
+later on with function prefix like done in the controller.
+
+
+Controller
+..........
+
+The controller is defined and implemented in `path_pcep_controller.[hc]`.
+Part of the controller code runs in FRR main thread and part runs in its own
+FRR pthread started to isolate the main thread from the PCCs' event loop.
+To communicate between the threads it uses FRR events, timers and
+`thread_execute` calls.
+
+
+PCC
+...
+
+Each PCC instance owns its state and runs in the controller thread. They are
+defined and implemented in `path_pcep_pcc.[hc]`. All the interactions with
+the daemon must pass through some controller's `pcep_thread_` prefixed function.
diff --git a/doc/developer/path-internals.rst b/doc/developer/path-internals.rst
new file mode 100644 (file)
index 0000000..2c2df0f
--- /dev/null
@@ -0,0 +1,11 @@
+.. _path_internals:
+
+*********
+Internals
+*********
+
+.. toctree::
+   :maxdepth: 2
+
+   path-internals-daemon
+   path-internals-pcep
diff --git a/doc/developer/path.rst b/doc/developer/path.rst
new file mode 100644 (file)
index 0000000..b6d2438
--- /dev/null
@@ -0,0 +1,11 @@
+.. _path:
+
+*****
+PATHD
+*****
+
+.. toctree::
+   :maxdepth: 2
+
+   path-internals
+
diff --git a/doc/developer/scripting.rst b/doc/developer/scripting.rst
new file mode 100644 (file)
index 0000000..b041361
--- /dev/null
@@ -0,0 +1,433 @@
+.. _scripting:
+
+Scripting
+=========
+
+.. seealso:: User docs for scripting
+
+Overview
+--------
+
+FRR has the ability to call Lua scripts to perform calculations, make
+decisions, or otherwise extend builtin behavior with arbitrary user code. This
+is implemented using the standard Lua C bindings. The supported version of Lua
+is 5.3.
+
+C objects may be passed into Lua and Lua objects may be retrieved by C code via
+a marshalling system. In this way, arbitrary data from FRR may be passed to
+scripts. It is possible to pass C functions as well.
+
+The Lua environment is isolated from the C environment; user scripts cannot
+access FRR's address space unless explicitly allowed by FRR.
+
+For general information on how Lua is used to extend C, refer to Part IV of
+"Programming in Lua".
+
+https://www.lua.org/pil/contents.html#24
+
+
+Design
+------
+
+Why Lua
+^^^^^^^
+
+Lua is designed to be embedded in C applications. It is very small; the
+standard library is 220K. It is relatively fast. It has a simple, minimal
+syntax that is relatively easy to learn and can be understood by someone with
+little to no programming experience. Moreover it is widely used to add
+scripting capabilities to applications. In short it is designed for this task.
+
+Reasons against supporting multiple scripting languages:
+
+- Each language would require different FFI methods, and specifically
+  different object encoders; a lot of code
+- Languages have different capabilities that would have to be brought to
+  parity with each other; a lot of work
+- Languages have vastly different performance characteristics; this would
+  create alot of basically unfixable issues, and result in a single de facto
+  standard scripting language (the fastest)
+- Each language would need a dedicated maintainer for the above reasons;
+  this is pragmatically difficult
+- Supporting multiple languages fractures the community and limits the audience
+  with which a given script can be shared
+
+General
+^^^^^^^
+
+FRR's concept of a script is somewhat abstracted away from the fact that it is
+Lua underneath. A script in has two things:
+
+- name
+- state
+
+In code:
+
+.. code-block:: c
+
+   struct frrscript {
+           /* Script name */
+           char *name;
+
+           /* Lua state */
+           struct lua_State *L;
+   };
+
+
+``name`` is simply a string. Everything else is in ``state``, which is itself a
+Lua library object (``lua_State``). This is an opaque struct that is
+manipulated using ``lua_*`` functions. The basic ones are imported from
+``lua.h`` and the rest are implemented within FRR to fill our use cases. The
+thing to remember is that all operations beyond the initial loading the script
+take place on this opaque state object.
+
+There are four basic actions that can be done on a script:
+
+- load
+- execute
+- query state
+- unload
+
+They are typically done in this order.
+
+
+Loading
+^^^^^^^
+
+A snippet of Lua code is referred to as a "chunk". These are simply text. FRR
+presently assumes chunks are located in individual files specific to one task.
+These files are stored in the scripts directory and must end in ``.lua``.
+
+A script object is created by loading a script. This is done with
+``frrscript_load()``. This function takes the name of the script and an
+optional callback function. The string ".lua" is appended to the script name,
+and the resultant filename is looked for in the scripts directory.
+
+For example, to load ``/etc/frr/scripts/bingus.lua``:
+
+.. code-block:: c
+
+   struct frrscript *fs = frrscript_load("bingus", NULL);
+
+During loading the script is validated for syntax and its initial environment
+is setup. By default this does not include the Lua standard library; there are
+security issues to consider, though for practical purposes untrusted users
+should not be able to write the scripts directory anyway. If desired the Lua
+standard library may be added to the script environment using
+``luaL_openlibs(fs->L)`` after loading the script. Further information on
+setting up the script environment is in the Lua manual.
+
+
+Executing
+^^^^^^^^^
+
+After loading, scripts may be executed. A script may take input in the form of
+variable bindings set in its environment prior to being run, and may provide
+results by setting the value of variables. Arbitrary C values may be
+transferred into the script environment, including functions.
+
+A typical execution call looks something like this:
+
+.. code-block:: c
+
+   struct frrscript *fs = frrscript_load(...);
+
+   int status_ok = 0, status_fail = 1;
+   struct prefix p = ...;
+
+   struct frrscript_env env[] = {
+           {"integer", "STATUS_FAIL", &status_fail},
+           {"integer", "STATUS_OK", &status_ok},
+           {"prefix", "myprefix", &p},
+           {}};
+
+   int result = frrscript_call(fs, env);
+
+
+To execute a loaded script, we need to define the inputs. These inputs are
+passed by binding values to variable names that will be accessible within the
+Lua environment. Basically, all communication with the script takes place via
+global variables within the script, and to provide inputs we predefine globals
+before the script runs. This is done by passing ``frrscript_call()`` an array
+of ``struct frrscript_env``. Each struct has three fields. The first identifies
+the type of the value being passed; more on this later. The second defines the
+name of the global variable within the script environment to bind the third
+argument (the value) to.
+
+The script is then executed and returns a general status code. In the success
+case this will be 0, otherwise it will be nonzero. The script itself does not
+determine this code, it is provided by the Lua interpreter.
+
+
+Querying State
+^^^^^^^^^^^^^^
+
+When a chunk is executed, its state at exit is preserved and can be inspected.
+
+After running a script, results may be retrieved by querying the script's
+state. Again this is done by retrieving the values of global variables, which
+are known to the script author to be "output" variables.
+
+A result is retrieved like so:
+
+.. code-block:: c
+
+   struct frrscript_env myresult = {"string", "myresult"};
+
+   char *myresult = frrscript_get_result(fs, &myresult);
+
+   ... do something ...
+
+   XFREE(MTYPE_TMP, myresult);
+
+
+As with arguments, results are retrieved by providing a ``struct
+frrscript_env`` specifying a type and a global name. No value is necessary, nor
+is it modified by ``frrscript_get_result()``. That function simply extracts the
+requested value from the script state and returns it.
+
+In most cases the returned value will be allocated with ``MTYPE_TMP`` and will
+need to be freed after use.
+
+
+Unloading
+^^^^^^^^^
+
+To destroy a script and its associated state:
+
+.. code-block:: c
+
+   frrscript_unload(fs);
+
+Values returned by ``frrscript_get_result`` are still valid after the script
+they were retrieved from is unloaded.
+
+Note that you must unload and then load the script if you want to reset its
+state, for example to run it again with different inputs. Otherwise the state
+from the previous run carries over into subsequent runs.
+
+
+.. _marshalling:
+
+Marshalling
+^^^^^^^^^^^
+
+Earlier sections glossed over the meaning of the type name field in ``struct
+frrscript_env`` and how data is passed between C and Lua. Lua, as a dynamically
+typed, garbage collected language, cannot directly use C values without some
+kind of marshalling / unmarshalling system to translate types between the two
+runtimes.
+
+Lua communicates with C code using a stack. C code wishing to provide data to
+Lua scripts must provide a function that marshalls the C data into a Lua
+representation and pushes it on the stack. C code wishing to retrieve data from
+Lua must provide a corresponding unmarshalling function that retrieves a Lua
+value from the stack and converts it to the corresponding C type. These two
+functions, together with a chosen name of the type they operate on, are
+referred to as ``codecs`` in FRR.
+
+A codec is defined as:
+
+.. code-block:: c
+
+   typedef void (*encoder_func)(lua_State *, const void *);
+   typedef void *(*decoder_func)(lua_State *, int);
+
+   struct frrscript_codec {
+           const char *typename;
+           encoder_func encoder;
+           decoder_func decoder;
+   };
+
+A typename string and two function pointers.
+
+``typename`` can be anything you want. For example, for the combined types of
+``struct prefix`` and its equivalent in Lua I have chosen the name ``prefix``.
+There is no restriction on naming here, it is just a human name used as a key
+and specified when passing and retrieving values.
+
+``encoder`` is a function that takes a ``lua_State *`` and a C type and pushes
+onto the Lua stack a value representing the C type. For C structs, the usual
+case, this will typically be a Lua table (tables are the only datastructure Lua
+has). For example, here is the encoder function for ``struct prefix``:
+
+
+.. code-block:: c
+
+   void lua_pushprefix(lua_State *L, const struct prefix *prefix)
+   {
+           char buffer[PREFIX_STRLEN];
+
+           zlog_debug("frrlua: pushing prefix table");
+
+           lua_newtable(L);
+           lua_pushstring(L, prefix2str(prefix, buffer, PREFIX_STRLEN));
+           lua_setfield(L, -2, "network");
+           lua_pushinteger(L, prefix->prefixlen);
+           lua_setfield(L, -2, "length");
+           lua_pushinteger(L, prefix->family);
+           lua_setfield(L, -2, "family");
+   }
+
+This function pushes a single value onto the Lua stack. It is a table whose equivalent in Lua is:
+
+.. code-block::
+
+   { ["network"] = "1.2.3.4/24", ["prefixlen"] = 24, ["family"] = 2 }
+
+
+``decoder`` does the reverse; it takes a ``lua_State *`` and an index into the
+stack, and unmarshalls a Lua value there into the corresponding C type. Again
+for ``struct prefix``:
+
+
+.. code-block:: c
+
+   void *lua_toprefix(lua_State *L, int idx)
+   {
+           struct prefix *p = XCALLOC(MTYPE_TMP, sizeof(struct prefix));
+
+           lua_getfield(L, idx, "network");
+           str2prefix(lua_tostring(L, -1), p);
+           lua_pop(L, 1);
+
+           return p;
+   }
+
+By convention these functions should be called ``lua_to*``, as this is the
+naming convention used by the Lua C library for the basic types e.g.
+``lua_tointeger`` and ``lua_tostring``.
+
+The returned data must always be copied off the stack and the copy must be
+allocated with ``MTYPE_TMP``. This way it is possible to unload the script
+(destroy the state) without invalidating any references to values stored in it.
+
+To register a new type with its corresponding encoding functions:
+
+.. code-block:: c
+
+   struct frrscript_codec frrscript_codecs_lib[] = {    
+             {.typename = "prefix",    
+              .encoder = (encoder_func)lua_pushprefix,    
+              .decoder = lua_toprefix},    
+             {.typename = "sockunion",    
+              .encoder = (encoder_func)lua_pushsockunion,    
+              .decoder = lua_tosockunion},    
+              ...
+              {}};
+
+   frrscript_register_type_codecs(frrscript_codecs_lib);
+
+From this point on the type names are available to be used when calling any
+script and getting its results.
+
+.. note::
+
+   Marshalled types are not restricted to simple values like integers, strings
+   and tables. It is possible to marshall a type such that the resultant object
+   in Lua is an actual object-oriented object, complete with methods that call
+   back into defined C functions. See the Lua manual for how to do this; for a
+   code example, look at how zlog is exported into the script environment.
+
+
+Script Environment
+------------------
+
+Logging
+^^^^^^^
+
+For convenience, script environments are populated by default with a ``log``
+object which contains methods corresponding to each of the ``zlog`` levels:
+
+.. code-block:: lua
+
+   log.info("info")
+   log.warn("warn")
+   log.error("error")
+   log.notice("notice")
+   log.debug("debug")
+
+The log messages will show up in the daemon's log output.
+
+
+Examples
+--------
+
+For a complete code example involving passing custom types, retrieving results,
+and doing complex calculations in Lua, look at the implementation of the
+``match script SCRIPT`` command for BGP routemaps. This example calls into a
+script with a route prefix and attributes received from a peer and expects the
+script to return a match / no match / match and update result.
+
+An example script to use with this follows. This script matches, does not match
+or updates a route depending on how many BGP UPDATE messages the peer has
+received when the script is called, simply as a demonstration of what can be
+accomplished with scripting.
+
+.. code-block:: lua
+
+
+   -- Example route map matching
+   -- author: qlyoung
+   --
+   -- The following variables are available to us:
+   --   log
+   --     logging library, with the usual functions
+   --   prefix
+   --     the route under consideration
+   --   attributes
+   --     the route's attributes
+   --   peer
+   --     the peer which received this route
+   --   RM_FAILURE
+   --     status code in case of failure
+   --   RM_NOMATCH
+   --     status code for no match
+   --   RM_MATCH
+   --     status code for match
+   --   RM_MATCH_AND_CHANGE
+   --     status code for match-and-set
+   --
+   -- We need to set the following out values:
+   --   action
+   --      Set to the appropriate status code to indicate what we did
+   --   attributes
+   --      Setting fields on here will propagate them back up to the caller if
+   --      'action' is set to RM_MATCH_AND_CHANGE.
+   
+   
+   log.info("Evaluating route " .. prefix.network .. " from peer " .. peer.remote_id.string)
+   
+   function on_match (prefix, attrs)
+           log.info("Match")
+           action = RM_MATCH
+   end
+   
+   function on_nomatch (prefix, attrs)
+           log.info("No match")
+           action = RM_NOMATCH
+   end
+   
+   function on_match_and_change (prefix, attrs)
+           action = RM_MATCH_AND_CHANGE
+           log.info("Match and change")
+           attrs["metric"] = attrs["metric"] + 7
+   end
+   
+   special_routes = {
+           ["172.16.10.4/24"] = on_match,
+           ["172.16.13.1/8"] = on_nomatch,
+           ["192.168.0.24/8"] = on_match_and_change,
+   }
+   
+   
+   if special_routes[prefix.network] then
+           special_routes[prefix.network](prefix, attributes)
+   elseif peer.stats.update_in % 3 == 0 then
+           on_match(prefix, attributes)
+   elseif peer.stats.update_in % 2 == 0 then
+           on_nomatch(prefix, attributes)
+   else
+           on_match_and_change(prefix, attributes)
+   end
+
index 57f885ecc18c3b3d13d5174014998303930f95c6..07a25886d0c2db65bbb8c3589611aa7d8c44e543 100644 (file)
@@ -11,6 +11,7 @@ dev_RSTFILES = \
        doc/developer/building-frr-for-debian8.rst \
        doc/developer/building-frr-for-debian9.rst \
        doc/developer/building-frr-for-fedora.rst \
+       doc/developer/building-frr-for-opensuse.rst \
        doc/developer/building-frr-for-freebsd10.rst \
        doc/developer/building-frr-for-freebsd11.rst \
        doc/developer/building-frr-for-freebsd9.rst \
@@ -32,10 +33,10 @@ dev_RSTFILES = \
        doc/developer/include-compile.rst \
        doc/developer/index.rst \
        doc/developer/library.rst \
+       doc/developer/link-state.rst \
        doc/developer/lists.rst \
        doc/developer/locking.rst \
        doc/developer/logging.rst \
-       doc/developer/lua.rst \
        doc/developer/memtypes.rst \
        doc/developer/modules.rst \
        doc/developer/next-hop-tracking.rst \
@@ -45,8 +46,14 @@ dev_RSTFILES = \
        doc/developer/packaging-debian.rst \
        doc/developer/packaging-redhat.rst \
        doc/developer/packaging.rst \
+       doc/developer/path-internals-daemon.rst \
+       doc/developer/path-internals-pcep.rst \
+       doc/developer/path-internals.rst \
+       doc/developer/path.rst \
        doc/developer/rcu.rst \
+       doc/developer/scripting.rst \
        doc/developer/static-linking.rst \
+       doc/developer/tracing.rst \
        doc/developer/testing.rst \
        doc/developer/topotests-snippets.rst \
        doc/developer/topotests.rst \
index 1c77cd7be1282b1a56b93c64f595f7e1d3fbde65..07f1f05114ccdf1c3d3ad91002d60dc6381b83a4 100644 (file)
@@ -95,7 +95,7 @@ The first step to write a new test is to define the topology and initial
 configuration. User has to define topology and initial configuration in JSON
 file. Here is an example of JSON file::
 
-   BGP neihghborship with single phy-link, sample JSON file:
+   BGP neighborship with single phy-link, sample JSON file:
    {
    "ipv4base": "192.168.0.0",
    "ipv4mask": 30,
index ee0a6be008d2d4e2ee7c5a54d05837200ff90e78..d54f6c7aaa8c9144ad8b05cd4f3ab07f66f1fc15 100644 (file)
@@ -57,7 +57,7 @@ run the target in non-forking mode (no ``-d``) and use LTTng as usual (refer to
 LTTng user manual). When using USDT probes with LTTng, follow the example in
 `this article
 <https://lttng.org/blog/2019/10/15/new-dynamic-user-space-tracing-in-lttng/>`_.
-To trace with dtrace or SystemTap, compile with :option:`--enable-usdt=yes` and
+To trace with dtrace or SystemTap, compile with `--enable-usdt=yes` and
 use your tracer as usual.
 
 To see available USDT probes::
index 4183ac6480c7a78d954aa4b959a8651c1d895ddb..861d87b998a62fc17ae16c66c911c62686b1e501 100644 (file)
@@ -1262,6 +1262,9 @@ When documented this way, CLI commands can be cross referenced with the
 This is very helpful for users who want to quickly remind themselves what a
 particular command does.
 
+When documenting a cli that has a ``no`` form, please do not include
+the ``no`` in the ``.. index::`` line.
+
 Configuration Snippets
 ^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/doc/figures/pcep_module_threading_overview.svg b/doc/figures/pcep_module_threading_overview.svg
new file mode 100644 (file)
index 0000000..4d2d2a2
--- /dev/null
@@ -0,0 +1,481 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.2" width="210mm" height="297mm" viewBox="0 0 21000 29700" preserveAspectRatio="xMidYMid" fill-rule="evenodd" stroke-width="28.222" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" xmlns:ooo="http://xml.openoffice.org/svg/export" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:presentation="http://sun.com/xmlns/staroffice/presentation" xmlns:smil="http://www.w3.org/2001/SMIL20/" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xml:space="preserve">
+ <defs class="ClipPathGroup">
+  <clipPath id="presentation_clip_path" clipPathUnits="userSpaceOnUse">
+   <rect x="0" y="0" width="21000" height="29700"/>
+  </clipPath>
+  <clipPath id="presentation_clip_path_shrink" clipPathUnits="userSpaceOnUse">
+   <rect x="21" y="29" width="20958" height="29641"/>
+  </clipPath>
+ </defs>
+ <defs>
+  <font id="EmbeddedFont_1" horiz-adv-x="2048">
+   <font-face font-family="Liberation Sans embedded" units-per-em="2048" font-weight="normal" font-style="normal" ascent="1852" descent="423"/>
+   <missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
+   <glyph unicode="u" horiz-adv-x="874" d="M 314,1082 L 314,396 C 314,325 321,269 335,230 349,191 371,162 402,145 433,128 478,119 537,119 624,119 692,149 742,208 792,267 817,350 817,455 L 817,1082 997,1082 997,231 C 997,105 999,28 1003,0 L 833,0 C 832,3 832,12 831,27 830,42 830,59 829,78 828,97 826,132 825,185 L 822,185 C 781,110 733,58 679,27 624,-4 557,-20 476,-20 357,-20 271,10 216,69 161,128 133,225 133,361 L 133,1082 314,1082 Z"/>
+   <glyph unicode="t" horiz-adv-x="531" d="M 554,8 C 495,-8 434,-16 372,-16 228,-16 156,66 156,229 L 156,951 31,951 31,1082 163,1082 216,1324 336,1324 336,1082 536,1082 536,951 336,951 336,268 C 336,216 345,180 362,159 379,138 408,127 450,127 474,127 509,132 554,141 L 554,8 Z"/>
+   <glyph unicode="r" horiz-adv-x="530" d="M 142,0 L 142,830 C 142,906 140,990 136,1082 L 306,1082 C 311,959 314,886 314,861 L 318,861 C 347,954 380,1017 417,1051 454,1085 507,1102 575,1102 599,1102 623,1099 648,1092 L 648,927 C 624,934 592,937 552,937 477,937 420,905 381,841 342,776 322,684 322,564 L 322,0 142,0 Z"/>
+   <glyph unicode="p" horiz-adv-x="953" d="M 1053,546 C 1053,169 920,-20 655,-20 488,-20 376,43 319,168 L 314,168 C 317,163 318,106 318,-2 L 318,-425 138,-425 138,861 C 138,972 136,1046 132,1082 L 306,1082 C 307,1079 308,1070 309,1054 310,1037 312,1012 314,978 315,944 316,921 316,908 L 320,908 C 352,975 394,1024 447,1055 500,1086 569,1101 655,1101 788,1101 888,1056 954,967 1020,878 1053,737 1053,546 Z M 864,542 C 864,693 844,800 803,865 762,930 698,962 609,962 538,962 482,947 442,917 401,887 371,840 350,777 329,713 318,630 318,528 318,386 341,281 386,214 431,147 505,113 607,113 696,113 762,146 803,212 844,277 864,387 864,542 Z"/>
+   <glyph unicode="o" horiz-adv-x="980" d="M 1053,542 C 1053,353 1011,212 928,119 845,26 724,-20 565,-20 407,-20 288,28 207,125 126,221 86,360 86,542 86,915 248,1102 571,1102 736,1102 858,1057 936,966 1014,875 1053,733 1053,542 Z M 864,542 C 864,691 842,800 798,868 753,935 679,969 574,969 469,969 393,935 346,866 299,797 275,689 275,542 275,399 298,292 345,221 391,149 464,113 563,113 671,113 748,148 795,217 841,286 864,395 864,542 Z"/>
+   <glyph unicode="n" horiz-adv-x="874" d="M 825,0 L 825,686 C 825,757 818,813 804,852 790,891 768,920 737,937 706,954 661,963 602,963 515,963 447,933 397,874 347,815 322,732 322,627 L 322,0 142,0 142,851 C 142,977 140,1054 136,1082 L 306,1082 C 307,1079 307,1070 308,1055 309,1040 310,1024 311,1005 312,986 313,950 314,897 L 317,897 C 358,972 406,1025 461,1056 515,1087 582,1102 663,1102 782,1102 869,1073 924,1014 979,955 1006,857 1006,721 L 1006,0 825,0 Z"/>
+   <glyph unicode="l" horiz-adv-x="187" d="M 138,0 L 138,1484 318,1484 318,0 138,0 Z"/>
+   <glyph unicode="i" horiz-adv-x="187" d="M 137,1312 L 137,1484 317,1484 317,1312 137,1312 Z M 137,0 L 137,1082 317,1082 317,0 137,0 Z"/>
+   <glyph unicode="h" horiz-adv-x="874" d="M 317,897 C 356,968 402,1020 457,1053 511,1086 580,1102 663,1102 780,1102 867,1073 923,1015 978,956 1006,858 1006,721 L 1006,0 825,0 825,686 C 825,762 818,819 804,856 790,893 767,920 735,937 703,954 659,963 602,963 517,963 450,934 399,875 348,816 322,737 322,638 L 322,0 142,0 142,1484 322,1484 322,1098 C 322,1057 321,1015 319,972 316,929 315,904 314,897 L 317,897 Z"/>
+   <glyph unicode="e" horiz-adv-x="980" d="M 276,503 C 276,379 302,283 353,216 404,149 479,115 578,115 656,115 719,131 766,162 813,193 844,233 861,281 L 1019,236 C 954,65 807,-20 578,-20 418,-20 296,28 213,123 129,218 87,360 87,548 87,727 129,864 213,959 296,1054 416,1102 571,1102 889,1102 1048,910 1048,527 L 1048,503 276,503 Z M 862,641 C 852,755 823,838 775,891 727,943 658,969 568,969 481,969 412,940 361,882 310,823 282,743 278,641 L 862,641 Z"/>
+   <glyph unicode="d" horiz-adv-x="927" d="M 821,174 C 788,105 744,55 689,25 634,-5 565,-20 484,-20 347,-20 247,26 183,118 118,210 86,349 86,536 86,913 219,1102 484,1102 566,1102 634,1087 689,1057 744,1027 788,979 821,914 L 823,914 821,1035 821,1484 1001,1484 1001,223 C 1001,110 1003,36 1007,0 L 835,0 C 833,11 831,35 829,74 826,113 825,146 825,174 L 821,174 Z M 275,542 C 275,391 295,282 335,217 375,152 440,119 530,119 632,119 706,154 752,225 798,296 821,405 821,554 821,697 798,802 752,869 706,936 633,969 532,969 441,969 376,936 336,869 295,802 275,693 275,542 Z"/>
+   <glyph unicode="c" horiz-adv-x="901" d="M 275,546 C 275,402 298,295 343,226 388,157 457,122 548,122 612,122 666,139 709,174 752,209 778,262 788,334 L 970,322 C 956,218 912,135 837,73 762,11 668,-20 553,-20 402,-20 286,28 207,124 127,219 87,359 87,542 87,724 127,863 207,959 287,1054 402,1102 551,1102 662,1102 754,1073 827,1016 900,959 945,880 964,779 L 779,765 C 770,825 746,873 708,908 670,943 616,961 546,961 451,961 382,929 339,866 296,803 275,696 275,546 Z"/>
+   <glyph unicode="b" horiz-adv-x="953" d="M 1053,546 C 1053,169 920,-20 655,-20 573,-20 505,-5 451,25 396,54 352,102 318,168 L 316,168 C 316,147 315,116 312,74 309,31 307,7 306,0 L 132,0 C 136,36 138,110 138,223 L 138,1484 318,1484 318,1061 C 318,1018 317,967 314,908 L 318,908 C 351,977 396,1027 451,1057 506,1087 574,1102 655,1102 792,1102 892,1056 957,964 1021,872 1053,733 1053,546 Z M 864,540 C 864,691 844,800 804,865 764,930 699,963 609,963 508,963 434,928 388,859 341,790 318,680 318,529 318,387 341,282 386,215 431,147 505,113 607,113 698,113 763,147 804,214 844,281 864,389 864,540 Z"/>
+   <glyph unicode="a" horiz-adv-x="1060" d="M 414,-20 C 305,-20 224,9 169,66 114,123 87,202 87,302 87,414 124,500 198,560 271,620 390,652 554,656 L 797,660 797,719 C 797,807 778,870 741,908 704,946 645,965 565,965 484,965 426,951 389,924 352,897 330,853 323,793 L 135,810 C 166,1005 310,1102 569,1102 705,1102 807,1071 876,1009 945,946 979,856 979,738 L 979,272 C 979,219 986,179 1000,152 1014,125 1041,111 1080,111 1097,111 1117,113 1139,118 L 1139,6 C 1094,-5 1047,-10 1000,-10 933,-10 885,8 855,43 824,78 807,132 803,207 L 797,207 C 751,124 698,66 637,32 576,-3 501,-20 414,-20 Z M 455,115 C 521,115 580,130 631,160 682,190 723,231 753,284 782,336 797,390 797,445 L 797,534 600,530 C 515,529 451,520 408,504 364,488 330,463 307,430 284,397 272,353 272,299 272,240 288,195 320,163 351,131 396,115 455,115 Z"/>
+   <glyph unicode="_" horiz-adv-x="1218" d="M -31,-407 L -31,-277 1162,-277 1162,-407 -31,-407 Z"/>
+   <glyph unicode="Y" horiz-adv-x="1298" d="M 777,584 L 777,0 587,0 587,584 45,1409 255,1409 684,738 1111,1409 1321,1409 777,584 Z"/>
+   <glyph unicode="X" horiz-adv-x="1298" d="M 1112,0 L 689,616 257,0 46,0 582,732 87,1409 298,1409 690,856 1071,1409 1282,1409 800,739 1323,0 1112,0 Z"/>
+   <glyph unicode="V" horiz-adv-x="1377" d="M 782,0 L 584,0 9,1409 210,1409 600,417 684,168 768,417 1156,1409 1357,1409 782,0 Z"/>
+   <glyph unicode="T" horiz-adv-x="1192" d="M 720,1253 L 720,0 530,0 530,1253 46,1253 46,1409 1204,1409 1204,1253 720,1253 Z"/>
+   <glyph unicode="S" horiz-adv-x="1192" d="M 1272,389 C 1272,259 1221,158 1120,87 1018,16 875,-20 690,-20 347,-20 148,99 93,338 L 278,375 C 299,290 345,228 414,189 483,149 578,129 697,129 820,129 916,150 983,193 1050,235 1083,297 1083,379 1083,425 1073,462 1052,491 1031,520 1001,543 963,562 925,581 880,596 827,609 774,622 716,635 652,650 541,675 456,699 399,724 341,749 295,776 262,807 229,837 203,872 186,913 168,954 159,1000 159,1053 159,1174 205,1267 298,1332 390,1397 522,1430 694,1430 854,1430 976,1406 1061,1357 1146,1308 1205,1224 1239,1106 L 1051,1073 C 1030,1148 991,1202 933,1236 875,1269 795,1286 692,1286 579,1286 493,1267 434,1230 375,1193 345,1137 345,1063 345,1020 357,984 380,956 403,927 436,903 479,884 522,864 609,840 738,811 781,801 825,791 868,781 911,770 952,758 991,744 1030,729 1067,712 1102,693 1136,674 1166,650 1191,622 1216,594 1236,561 1251,523 1265,485 1272,440 1272,389 Z"/>
+   <glyph unicode="R" horiz-adv-x="1244" d="M 1164,0 L 798,585 359,585 359,0 168,0 168,1409 831,1409 C 990,1409 1112,1374 1199,1303 1285,1232 1328,1133 1328,1006 1328,901 1298,813 1237,742 1176,671 1091,626 984,607 L 1384,0 1164,0 Z M 1136,1004 C 1136,1086 1108,1149 1053,1192 997,1235 917,1256 812,1256 L 359,1256 359,736 820,736 C 921,736 999,760 1054,807 1109,854 1136,919 1136,1004 Z"/>
+   <glyph unicode="P" horiz-adv-x="1112" d="M 1258,985 C 1258,852 1215,746 1128,667 1041,588 922,549 773,549 L 359,549 359,0 168,0 168,1409 761,1409 C 919,1409 1041,1372 1128,1298 1215,1224 1258,1120 1258,985 Z M 1066,983 C 1066,1165 957,1256 738,1256 L 359,1256 359,700 746,700 C 959,700 1066,794 1066,983 Z"/>
+   <glyph unicode="O" horiz-adv-x="1430" d="M 1495,711 C 1495,564 1467,435 1411,324 1354,213 1273,128 1168,69 1063,10 938,-20 795,-20 650,-20 526,9 421,68 316,127 235,212 180,323 125,434 97,563 97,711 97,936 159,1113 282,1240 405,1367 577,1430 797,1430 940,1430 1065,1402 1170,1345 1275,1288 1356,1205 1412,1096 1467,987 1495,859 1495,711 Z M 1300,711 C 1300,886 1256,1024 1169,1124 1081,1224 957,1274 797,1274 636,1274 511,1225 423,1126 335,1027 291,889 291,711 291,534 336,394 425,291 514,187 637,135 795,135 958,135 1083,185 1170,286 1257,386 1300,528 1300,711 Z"/>
+   <glyph unicode="N" horiz-adv-x="1165" d="M 1082,0 L 328,1200 333,1103 338,936 338,0 168,0 168,1409 390,1409 1152,201 C 1144,332 1140,426 1140,485 L 1140,1409 1312,1409 1312,0 1082,0 Z"/>
+   <glyph unicode="M" horiz-adv-x="1377" d="M 1366,0 L 1366,940 C 1366,1044 1369,1144 1375,1240 1342,1121 1313,1027 1287,960 L 923,0 789,0 420,960 364,1130 331,1240 334,1129 338,940 338,0 168,0 168,1409 419,1409 794,432 C 807,393 820,351 833,306 845,261 853,228 857,208 862,235 874,275 891,330 908,384 919,418 925,432 L 1293,1409 1538,1409 1538,0 1366,0 Z"/>
+   <glyph unicode="L" horiz-adv-x="927" d="M 168,0 L 168,1409 359,1409 359,156 1071,156 1071,0 168,0 Z"/>
+   <glyph unicode="I" horiz-adv-x="213" d="M 189,0 L 189,1409 380,1409 380,0 189,0 Z"/>
+   <glyph unicode="H" horiz-adv-x="1165" d="M 1121,0 L 1121,653 359,653 359,0 168,0 168,1409 359,1409 359,813 1121,813 1121,1409 1312,1409 1312,0 1121,0 Z"/>
+   <glyph unicode="F" horiz-adv-x="1006" d="M 359,1253 L 359,729 1145,729 1145,571 359,571 359,0 168,0 168,1409 1169,1409 1169,1253 359,1253 Z"/>
+   <glyph unicode="E" horiz-adv-x="1138" d="M 168,0 L 168,1409 1237,1409 1237,1253 359,1253 359,801 1177,801 1177,647 359,647 359,156 1278,156 1278,0 168,0 Z"/>
+   <glyph unicode="D" horiz-adv-x="1218" d="M 1381,719 C 1381,574 1353,447 1296,338 1239,229 1159,145 1055,87 951,29 831,0 695,0 L 168,0 168,1409 634,1409 C 873,1409 1057,1349 1187,1230 1316,1110 1381,940 1381,719 Z M 1189,719 C 1189,894 1141,1027 1046,1119 950,1210 811,1256 630,1256 L 359,1256 359,153 673,153 C 776,153 867,176 946,221 1024,266 1084,332 1126,417 1168,502 1189,603 1189,719 Z"/>
+   <glyph unicode="C" horiz-adv-x="1324" d="M 792,1274 C 636,1274 515,1224 428,1124 341,1023 298,886 298,711 298,538 343,400 434,295 524,190 646,137 800,137 997,137 1146,235 1245,430 L 1401,352 C 1343,231 1262,138 1157,75 1052,12 930,-20 791,-20 649,-20 526,10 423,69 319,128 240,212 186,322 131,431 104,561 104,711 104,936 165,1112 286,1239 407,1366 575,1430 790,1430 940,1430 1065,1401 1166,1342 1267,1283 1341,1196 1388,1081 L 1207,1021 C 1174,1103 1122,1166 1050,1209 977,1252 891,1274 792,1274 Z"/>
+   <glyph unicode="B" horiz-adv-x="1112" d="M 1258,397 C 1258,272 1212,174 1121,105 1030,35 903,0 740,0 L 168,0 168,1409 680,1409 C 1011,1409 1176,1295 1176,1067 1176,984 1153,914 1106,857 1059,800 993,762 908,743 1020,730 1106,692 1167,631 1228,569 1258,491 1258,397 Z M 984,1044 C 984,1120 958,1174 906,1207 854,1240 779,1256 680,1256 L 359,1256 359,810 680,810 C 782,810 858,829 909,868 959,906 984,965 984,1044 Z M 1065,412 C 1065,578 948,661 715,661 L 359,661 359,153 730,153 C 847,153 932,175 985,218 1038,261 1065,326 1065,412 Z"/>
+   <glyph unicode="A" horiz-adv-x="1377" d="M 1167,0 L 1006,412 364,412 202,0 4,0 579,1409 796,1409 1362,0 1167,0 Z M 685,1265 L 676,1237 C 659,1182 635,1111 602,1024 L 422,561 949,561 768,1026 C 749,1072 731,1124 712,1182 L 685,1265 Z"/>
+   <glyph unicode=" " horiz-adv-x="556"/>
+  </font>
+ </defs>
+ <defs class="TextShapeIndex">
+  <g ooo:slide="id1" ooo:id-list="id3 id4 id5 id6 id7 id8 id9 id10 id11 id12 id13 id14 id15 id16 id17 id18 id19 id20 id21 id22 id23 id24 id25 id26 id27 id28"/>
+ </defs>
+ <defs class="EmbeddedBulletChars">
+  <g id="bullet-char-template-57356" transform="scale(0.00048828125,-0.00048828125)">
+   <path d="M 580,1141 L 1163,571 580,0 -4,571 580,1141 Z"/>
+  </g>
+  <g id="bullet-char-template-57354" transform="scale(0.00048828125,-0.00048828125)">
+   <path d="M 8,1128 L 1137,1128 1137,0 8,0 8,1128 Z"/>
+  </g>
+  <g id="bullet-char-template-10146" transform="scale(0.00048828125,-0.00048828125)">
+   <path d="M 174,0 L 602,739 174,1481 1456,739 174,0 Z M 1358,739 L 309,1346 659,739 1358,739 Z"/>
+  </g>
+  <g id="bullet-char-template-10132" transform="scale(0.00048828125,-0.00048828125)">
+   <path d="M 2015,739 L 1276,0 717,0 1260,543 174,543 174,936 1260,936 717,1481 1274,1481 2015,739 Z"/>
+  </g>
+  <g id="bullet-char-template-10007" transform="scale(0.00048828125,-0.00048828125)">
+   <path d="M 0,-2 C -7,14 -16,27 -25,37 L 356,567 C 262,823 215,952 215,954 215,979 228,992 255,992 264,992 276,990 289,987 310,991 331,999 354,1012 L 381,999 492,748 772,1049 836,1024 860,1049 C 881,1039 901,1025 922,1006 886,937 835,863 770,784 769,783 710,716 594,584 L 774,223 C 774,196 753,168 711,139 L 727,119 C 717,90 699,76 672,76 641,76 570,178 457,381 L 164,-76 C 142,-110 111,-127 72,-127 30,-127 9,-110 8,-76 1,-67 -2,-52 -2,-32 -2,-23 -1,-13 0,-2 Z"/>
+  </g>
+  <g id="bullet-char-template-10004" transform="scale(0.00048828125,-0.00048828125)">
+   <path d="M 285,-33 C 182,-33 111,30 74,156 52,228 41,333 41,471 41,549 55,616 82,672 116,743 169,778 240,778 293,778 328,747 346,684 L 369,508 C 377,444 397,411 428,410 L 1163,1116 C 1174,1127 1196,1133 1229,1133 1271,1133 1292,1118 1292,1087 L 1292,965 C 1292,929 1282,901 1262,881 L 442,47 C 390,-6 338,-33 285,-33 Z"/>
+  </g>
+  <g id="bullet-char-template-9679" transform="scale(0.00048828125,-0.00048828125)">
+   <path d="M 813,0 C 632,0 489,54 383,161 276,268 223,411 223,592 223,773 276,916 383,1023 489,1130 632,1184 813,1184 992,1184 1136,1130 1245,1023 1353,916 1407,772 1407,592 1407,412 1353,268 1245,161 1136,54 992,0 813,0 Z"/>
+  </g>
+  <g id="bullet-char-template-8226" transform="scale(0.00048828125,-0.00048828125)">
+   <path d="M 346,457 C 273,457 209,483 155,535 101,586 74,649 74,723 74,796 101,859 155,911 209,963 273,989 346,989 419,989 480,963 531,910 582,859 608,796 608,723 608,648 583,586 532,535 482,483 420,457 346,457 Z"/>
+  </g>
+  <g id="bullet-char-template-8211" transform="scale(0.00048828125,-0.00048828125)">
+   <path d="M -4,459 L 1135,459 1135,606 -4,606 -4,459 Z"/>
+  </g>
+  <g id="bullet-char-template-61548" transform="scale(0.00048828125,-0.00048828125)">
+   <path d="M 173,740 C 173,903 231,1043 346,1159 462,1274 601,1332 765,1332 928,1332 1067,1274 1183,1159 1299,1043 1357,903 1357,740 1357,577 1299,437 1183,322 1067,206 928,148 765,148 601,148 462,206 346,322 231,437 173,577 173,740 Z"/>
+  </g>
+ </defs>
+ <defs class="TextEmbeddedBitmaps"/>
+ <g>
+  <g id="id2" class="Master_Slide">
+   <g id="bg-id2" class="Background"/>
+   <g id="bo-id2" class="BackgroundObjects"/>
+  </g>
+ </g>
+ <g class="SlideGroup">
+  <g>
+   <g id="container-id1">
+    <g id="id1" class="Slide" clip-path="url(#presentation_clip_path)">
+     <g class="Page">
+      <g class="com.sun.star.drawing.CustomShape">
+       <g id="id3">
+        <rect class="BoundingBox" stroke="none" fill="none" x="9227" y="2229" width="7040" height="8959"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12771,11160 L 12747,11160 12642,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12578,11160 L 12474,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12410,11160 L 12306,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12242,11160 L 12138,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12074,11160 L 11970,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11906,11160 L 11802,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11738,11160 L 11634,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11570,11160 L 11466,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11402,11160 L 11298,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11234,11160 L 11130,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11066,11160 L 10962,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10898,11160 L 10794,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10730,11160 L 10626,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10562,11160 L 10458,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10394,11160 L 10290,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10226,11160 L 10122,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10058,11160 L 9954,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9890,11160 L 9786,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9722,11160 L 9618,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9554,11160 L 9450,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9386,11160 L 9282,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,11124 L 9254,11020"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,10956 L 9254,10852"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,10788 L 9254,10684"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,10620 L 9254,10516"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,10452 L 9254,10348"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,10284 L 9254,10180"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,10116 L 9254,10012"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,9948 L 9254,9844"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,9780 L 9254,9676"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,9612 L 9254,9508"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,9444 L 9254,9340"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,9276 L 9254,9172"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,9108 L 9254,9004"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,8940 L 9254,8836"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,8772 L 9254,8668"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,8604 L 9254,8500"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,8436 L 9254,8332"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,8268 L 9254,8164"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,8100 L 9254,7996"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,7932 L 9254,7828"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,7764 L 9254,7660"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,7596 L 9254,7492"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,7428 L 9254,7324"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,7260 L 9254,7156"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,7092 L 9254,6988"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,6924 L 9254,6820"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,6756 L 9254,6652"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,6588 L 9254,6484"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,6420 L 9254,6316"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,6252 L 9254,6148"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,6084 L 9254,5980"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,5916 L 9254,5812"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,5748 L 9254,5644"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,5580 L 9254,5476"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,5412 L 9254,5308"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,5244 L 9254,5140"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,5076 L 9254,4972"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,4908 L 9254,4804"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,4740 L 9254,4636"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,4572 L 9254,4467"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,4404 L 9254,4299"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,4236 L 9254,4131"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,4068 L 9254,3963"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,3900 L 9254,3795"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,3732 L 9254,3627"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,3564 L 9254,3459"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,3396 L 9254,3291"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,3228 L 9254,3123"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,3060 L 9254,2955"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,2892 L 9254,2787"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,2724 L 9254,2619"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,2556 L 9254,2451"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9254,2388 L 9254,2283"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9290,2256 L 9395,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9458,2256 L 9563,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9626,2256 L 9731,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9794,2256 L 9899,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 9962,2256 L 10067,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10130,2256 L 10235,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10298,2256 L 10403,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10466,2256 L 10571,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10634,2256 L 10739,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10802,2256 L 10907,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 10970,2256 L 11075,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11138,2256 L 11243,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11306,2256 L 11411,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11474,2256 L 11579,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11642,2256 L 11747,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11810,2256 L 11915,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 11978,2256 L 12083,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12146,2256 L 12251,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12314,2256 L 12419,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12482,2256 L 12587,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12650,2256 L 12755,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12818,2256 L 12923,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12986,2256 L 13091,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13154,2256 L 13259,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13322,2256 L 13427,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13490,2256 L 13595,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13659,2256 L 13763,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13827,2256 L 13931,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13995,2256 L 14099,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14163,2256 L 14267,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14331,2256 L 14435,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14499,2256 L 14603,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14667,2256 L 14771,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14835,2256 L 14939,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15003,2256 L 15107,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15171,2256 L 15275,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15339,2256 L 15443,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15507,2256 L 15611,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15675,2256 L 15779,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15843,2256 L 15947,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16011,2256 L 16115,2256"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16179,2256 L 16239,2256 16239,2300"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,2364 L 16239,2468"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,2532 L 16239,2636"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,2700 L 16239,2804"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,2868 L 16239,2972"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,3036 L 16239,3140"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,3204 L 16239,3308"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,3372 L 16239,3476"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,3540 L 16239,3644"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,3708 L 16239,3812"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,3876 L 16239,3980"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,4044 L 16239,4148"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,4212 L 16239,4316"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,4380 L 16239,4484"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,4548 L 16239,4652"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,4716 L 16239,4820"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,4884 L 16239,4988"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,5052 L 16239,5156"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,5220 L 16239,5324"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,5388 L 16239,5492"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,5556 L 16239,5660"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,5724 L 16239,5828"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,5892 L 16239,5996"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,6060 L 16239,6164"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,6228 L 16239,6332"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,6396 L 16239,6500"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,6564 L 16239,6668"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,6732 L 16239,6836"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,6900 L 16239,7004"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,7068 L 16239,7172"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,7236 L 16239,7340"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,7404 L 16239,7508"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,7572 L 16239,7676"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,7740 L 16239,7844"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,7908 L 16239,8012"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,8076 L 16239,8180"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,8244 L 16239,8348"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,8412 L 16239,8516"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,8580 L 16239,8684"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,8748 L 16239,8852"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,8916 L 16239,9020"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,9084 L 16239,9188"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,9252 L 16239,9356"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,9420 L 16239,9524"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,9588 L 16239,9693"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,9756 L 16239,9861"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,9924 L 16239,10029"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,10092 L 16239,10197"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,10260 L 16239,10365"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,10428 L 16239,10533"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,10596 L 16239,10701"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,10764 L 16239,10869"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,10932 L 16239,11037"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16239,11100 L 16239,11160 16194,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16131,11160 L 16026,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15963,11160 L 15858,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15795,11160 L 15690,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15627,11160 L 15522,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15459,11160 L 15354,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15291,11160 L 15186,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15123,11160 L 15018,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14955,11160 L 14850,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14787,11160 L 14682,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14619,11160 L 14514,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14451,11160 L 14346,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14283,11160 L 14178,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14115,11160 L 14010,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13947,11160 L 13842,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13779,11160 L 13674,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13611,11160 L 13506,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13443,11160 L 13338,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13275,11160 L 13170,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 13107,11160 L 13002,11160"/>
+        <path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 12939,11160 L 12834,11160"/>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.TextShape">
+       <g id="id4">
+        <rect class="BoundingBox" stroke="none" fill="none" x="3128" y="2360" width="5723" height="840"/>
+        <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="529px" font-weight="400"><tspan class="TextPosition" x="3378" y="2963"><tspan fill="rgb(0,102,179)" stroke="none">MAIN PTHREAD</tspan></tspan></tspan></text>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.TextShape">
+       <g id="id5">
+        <rect class="BoundingBox" stroke="none" fill="none" x="9640" y="2360" width="8013" height="840"/>
+        <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="529px" font-weight="400"><tspan class="TextPosition" x="9890" y="2963"><tspan fill="rgb(0,102,179)" stroke="none">CONTROLLER PTHREAD</tspan></tspan></tspan></text>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.CustomShape">
+       <g id="id6">
+        <rect class="BoundingBox" stroke="none" fill="none" x="3315" y="5190" width="2797" height="1273"/>
+        <path fill="rgb(114,159,207)" stroke="none" d="M 4713,6461 L 3316,6461 3316,5191 6110,5191 6110,6461 4713,6461 Z"/>
+        <path fill="none" stroke="rgb(52,101,164)" d="M 4713,6461 L 3316,6461 3316,5191 6110,5191 6110,6461 4713,6461 Z"/>
+        <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="4358" y="5985"><tspan fill="rgb(0,0,0)" stroke="none">CLI</tspan></tspan></tspan></text>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.CustomShape">
+       <g id="id7">
+        <rect class="BoundingBox" stroke="none" fill="none" x="3315" y="7349" width="2797" height="1273"/>
+        <path fill="rgb(114,159,207)" stroke="none" d="M 4713,8620 L 3316,8620 3316,7350 6110,7350 6110,8620 4713,8620 Z"/>
+        <path fill="none" stroke="rgb(52,101,164)" d="M 4713,8620 L 3316,8620 3316,7350 6110,7350 6110,8620 4713,8620 Z"/>
+        <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="3972" y="7888"><tspan fill="rgb(0,0,0)" stroke="none">PATHD</tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="3430" y="8400"><tspan fill="rgb(0,0,0)" stroke="none">INTERFACE</tspan></tspan></tspan></text>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.CustomShape">
+       <g id="id8">
+        <rect class="BoundingBox" stroke="none" fill="none" x="12459" y="6079" width="2797" height="1273"/>
+        <path fill="rgb(114,159,207)" stroke="none" d="M 13857,7350 L 12460,7350 12460,6080 15254,6080 15254,7350 13857,7350 Z"/>
+        <path fill="none" stroke="rgb(52,101,164)" d="M 13857,7350 L 12460,7350 12460,6080 15254,6080 15254,7350 13857,7350 Z"/>
+        <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="13375" y="6874"><tspan fill="rgb(0,0,0)" stroke="none">PCC</tspan></tspan></tspan></text>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.LineShape">
+       <g id="id9">
+        <rect class="BoundingBox" stroke="none" fill="none" x="1665" y="7578" width="2033" height="205"/>
+        <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 1956,7680 L 3406,7680"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 1665,7680 L 1970,7782 1970,7579 1665,7680 Z"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 3697,7680 L 3393,7579 3393,7782 3697,7680 Z"/>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.TextShape">
+       <g id="id10">
+        <rect class="BoundingBox" stroke="none" fill="none" x="1892" y="5137" width="1451" height="570"/>
+        <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="2142" y="5520"><tspan fill="rgb(0,0,0)" stroke="none">VTYSH</tspan></tspan></tspan></text>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.TextShape">
+       <g id="id11">
+        <rect class="BoundingBox" stroke="none" fill="none" x="1568" y="5738" width="1976" height="570"/>
+        <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="1818" y="6121"><tspan fill="rgb(0,0,0)" stroke="none">Northbound</tspan></tspan></tspan></text>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.TextShape">
+       <g id="id12">
+        <rect class="BoundingBox" stroke="none" fill="none" x="1738" y="7235" width="1735" height="570"/>
+        <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="1988" y="7618"><tspan fill="rgb(0,0,0)" stroke="none">pathd API</tspan></tspan></tspan></text>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.ClosedBezierShape">
+       <g id="id13">
+        <rect class="BoundingBox" stroke="none" fill="none" x="2299" y="2229" width="6957" height="8959"/>
+        <path fill="rgb(52,101,164)" stroke="none" d="M 2299,11134 L 2396,11134 2396,11160 2396,11186 2299,11186 2299,11134 Z M 2299,2230 L 2333,2230 2333,2256 2333,2283 2299,2283 2299,2230 Z M 2399,2283 L 2399,2256 2399,2230 2506,2230 2506,2256 2506,2283 2399,2283 Z M 2571,2283 L 2571,2256 2571,2230 2679,2230 2679,2256 2679,2283 2571,2283 Z M 2744,2283 L 2744,2256 2744,2230 2852,2230 2852,2256 2852,2283 2744,2283 Z M 2917,2283 L 2917,2256 2917,2230 3025,2230 3025,2256 3025,2283 2917,2283 Z M 3090,2283 L 3090,2256 3090,2230 3198,2230 3198,2256 3198,2283 3090,2283 Z M 3263,2283 L 3263,2256 3263,2230 3371,2230 3371,2256 3371,2283 3263,2283 Z M 3436,2283 L 3436,2256 3436,2230 3543,2230 3543,2256 3543,2283 3436,2283 Z M 3609,2283 L 3609,2256 3609,2230 3716,2230 3716,2256 3716,2283 3609,2283 Z M 3782,2283 L 3782,2256 3782,2230 3889,2230 3889,2256 3889,2283 3782,2283 Z M 3955,2283 L 3955,2256 3955,2230 4062,2230 4062,2256 4062,2283 3955,2283 Z M 4128,2283 L 4128,2256 4128,2230 4235,2230 4235,2256 4235,2283 4128,2283 Z M 4301,2283 L 4301,2256 4301,2230 4408,2230 4408,2256 4408,2283 4301,2283 Z M 4473,2283 L 4473,2256 4473,2230 4581,2230 4581,2256 4581,2283 4473,2283 Z M 4646,2283 L 4646,2256 4646,2230 4754,2230 4754,2256 4754,2283 4646,2283 Z M 4819,2283 L 4819,2256 4819,2230 4927,2230 4927,2256 4927,2283 4819,2283 Z M 4992,2283 L 4992,2256 4992,2230 5100,2230 5100,2256 5100,2283 4992,2283 Z M 5165,2283 L 5165,2256 5165,2230 5273,2230 5273,2256 5273,2283 5165,2283 Z M 5338,2283 L 5338,2256 5338,2230 5445,2230 5445,2256 5445,2283 5338,2283 Z M 5511,2283 L 5511,2256 5511,2230 5618,2230 5618,2256 5618,2283 5511,2283 Z M 5684,2283 L 5684,2256 5684,2230 5791,2230 5791,2256 5791,2283 5684,2283 Z M 5857,2283 L 5857,2256 5857,2230 5964,2230 5964,2256 5964,2283 5857,2283 Z M 6030,2283 L 6030,2256 6030,2230 6137,2230 6137,2256 6137,2283 6030,2283 Z M 6203,2283 L 6203,2256 6203,2230 6310,2230 6310,2256 6310,2283 6203,2283 Z M 6375,2283 L 6375,2256 6375,2230 6483,2230 6483,2256 6483,2283 6375,2283 Z M 6548,2283 L 6548,2256 6548,2230 6656,2230 6656,2256 6656,2283 6548,2283 Z M 6721,2283 L 6721,2256 6721,2230 6829,2230 6829,2256 6829,2283 6721,2283 Z M 6894,2283 L 6894,2256 6894,2230 7002,2230 7002,2256 7002,2283 6894,2283 Z M 7067,2283 L 7067,2256 7067,2230 7175,2230 7175,2256 7175,2283 7067,2283 Z M 7240,2283 L 7240,2256 7240,2230 7347,2230 7347,2256 7347,2283 7240,2283 Z M 7413,2283 L 7413,2256 7413,2230 7520,2230 7520,2256 7520,2283 7413,2283 Z M 7586,2283 L 7586,2256 7586,2230 7693,2230 7693,2256 7693,2283 7586,2283 Z M 7759,2283 L 7759,2256 7759,2230 7866,2230 7866,2256 7866,2283 7759,2283 Z M 7932,2283 L 7932,2256 7932,2230 8039,2230 8039,2256 8039,2283 7932,2283 Z M 8105,2283 L 8105,2256 8105,2230 8212,2230 8212,2256 8212,2283 8105,2283 Z M 8277,2283 L 8277,2256 8277,2230 8385,2230 8385,2256 8385,2283 8277,2283 Z M 8450,2283 L 8450,2256 8450,2230 8558,2230 8558,2256 8558,2283 8450,2283 Z M 8623,2283 L 8623,2256 8623,2230 8731,2230 8731,2256 8731,2283 8623,2283 Z M 8796,2283 L 8796,2256 8796,2230 8904,2230 8904,2256 8904,2283 8796,2283 Z M 8969,2283 L 8969,2256 8969,2230 9077,2230 9077,2256 9077,2283 8969,2283 Z M 9142,2283 L 9142,2256 9142,2230 9227,2230 C 9232,2230 9237,2231 9241,2233 9245,2235 9248,2239 9251,2243 9253,2247 9254,2251 9254,2256 L 9254,2278 9227,2278 9227,2283 9142,2283 Z M 9200,2341 L 9227,2341 9254,2341 9254,2446 9227,2446 9200,2446 9200,2341 Z M 9200,2509 L 9227,2509 9254,2509 9254,2614 9227,2614 9200,2614 9200,2509 Z M 9200,2677 L 9227,2677 9254,2677 9254,2782 9227,2782 9200,2782 9200,2677 Z M 9200,2845 L 9227,2845 9254,2845 9254,2950 9227,2950 9200,2950 9200,2845 Z M 9200,3013 L 9227,3013 9254,3013 9254,3118 9227,3118 9200,3118 9200,3013 Z M 9200,3181 L 9227,3181 9254,3181 9254,3286 9227,3286 9200,3286 9200,3181 Z M 9200,3349 L 9227,3349 9254,3349 9254,3454 9227,3454 9200,3454 9200,3349 Z M 9200,3517 L 9227,3517 9254,3517 9254,3622 9227,3622 9200,3622 9200,3517 Z M 9200,3685 L 9227,3685 9254,3685 9254,3790 9227,3790 9200,3790 9200,3685 Z M 9200,3853 L 9227,3853 9254,3853 9254,3958 9227,3958 9200,3958 9200,3853 Z M 9200,4021 L 9227,4021 9254,4021 9254,4126 9227,4126 9200,4126 9200,4021 Z M 9200,4189 L 9227,4189 9254,4189 9254,4294 9227,4294 9200,4294 9200,4189 Z M 9200,4357 L 9227,4357 9254,4357 9254,4462 9227,4462 9200,4462 9200,4357 Z M 9200,4525 L 9227,4525 9254,4525 9254,4630 9227,4630 9200,4630 9200,4525 Z M 9200,4693 L 9227,4693 9254,4693 9254,4798 9227,4798 9200,4798 9200,4693 Z M 9200,4861 L 9227,4861 9254,4861 9254,4966 9227,4966 9200,4966 9200,4861 Z M 9200,5029 L 9227,5029 9254,5029 9254,5134 9227,5134 9200,5134 9200,5029 Z M 9200,5197 L 9227,5197 9254,5197 9254,5302 9227,5302 9200,5302 9200,5197 Z M 9200,5365 L 9227,5365 9254,5365 9254,5470 9227,5470 9200,5470 9200,5365 Z M 9200,5533 L 9227,5533 9254,5533 9254,5638 9227,5638 9200,5638 9200,5533 Z M 9200,5701 L 9227,5701 9254,5701 9254,5806 9227,5806 9200,5806 9200,5701 Z M 9200,5869 L 9227,5869 9254,5869 9254,5974 9227,5974 9200,5974 9200,5869 Z M 9200,6037 L 9227,6037 9254,6037 9254,6142 9227,6142 9200,6142 9200,6037 Z M 9200,6205 L 9227,6205 9254,6205 9254,6310 9227,6310 9200,6310 9200,6205 Z M 9200,6373 L 9227,6373 9254,6373 9254,6478 9227,6478 9200,6478 9200,6373 Z M 9200,6541 L 9227,6541 9254,6541 9254,6646 9227,6646 9200,6646 9200,6541 Z M 9200,6709 L 9227,6709 9254,6709 9254,6814 9227,6814 9200,6814 9200,6709 Z M 9200,6877 L 9227,6877 9254,6877 9254,6982 9227,6982 9200,6982 9200,6877 Z M 9200,7045 L 9227,7045 9254,7045 9254,7150 9227,7150 9200,7150 9200,7045 Z M 9200,7213 L 9227,7213 9254,7213 9254,7318 9227,7318 9200,7318 9200,7213 Z M 9200,7381 L 9227,7381 9254,7381 9254,7486 9227,7486 9200,7486 9200,7381 Z M 9200,7549 L 9227,7549 9254,7549 9254,7654 9227,7654 9200,7654 9200,7549 Z M 9200,7717 L 9227,7717 9254,7717 9254,7822 9227,7822 9200,7822 9200,7717 Z M 9200,7886 L 9227,7886 9254,7886 9254,7990 9227,7990 9200,7990 9200,7886 Z M 9200,8054 L 9227,8054 9254,8054 9254,8158 9227,8158 9200,8158 9200,8054 Z M 9200,8222 L 9227,8222 9254,8222 9254,8326 9227,8326 9200,8326 9200,8222 Z M 9200,8390 L 9227,8390 9254,8390 9254,8494 9227,8494 9200,8494 9200,8390 Z M 9200,8558 L 9227,8558 9254,8558 9254,8662 9227,8662 9200,8662 9200,8558 Z M 9200,8726 L 9227,8726 9254,8726 9254,8830 9227,8830 9200,8830 9200,8726 Z M 9200,8894 L 9227,8894 9254,8894 9254,8998 9227,8998 9200,8998 9200,8894 Z M 9200,9062 L 9227,9062 9254,9062 9254,9166 9227,9166 9200,9166 9200,9062 Z M 9200,9230 L 9227,9230 9254,9230 9254,9334 9227,9334 9200,9334 9200,9230 Z M 9200,9398 L 9227,9398 9254,9398 9254,9502 9227,9502 9200,9502 9200,9398 Z M 9200,9566 L 9227,9566 9254,9566 9254,9670 9227,9670 9200,9670 9200,9566 Z M 9200,9734 L 9227,9734 9254,9734 9254,9838 9227,9838 9200,9838 9200,9734 Z M 9200,9902 L 9227,9902 9254,9902 9254,10006 9227,10006 9200,10006 9200,9902 Z M 9200,10070 L 9227,10070 9254,10070 9254,10174 9227,10174 9200,10174 9200,10070 Z M 9200,10238 L 9227,10238 9254,10238 9254,10342 9227,10342 9200,10342 9200,10238 Z M 9200,10406 L 9227,10406 9254,10406 9254,10510 9227,10510 9200,10510 9200,10406 Z M 9200,10574 L 9227,10574 9254,10574 9254,10678 9227,10678 9200,10678 9200,10574 Z M 9200,10742 L 9227,10742 9254,10742 9254,10846 9227,10846 9200,10846 9200,10742 Z M 9200,10910 L 9227,10910 9254,10910 9254,11014 9227,11014 9200,11014 9200,10910 Z M 9200,11078 L 9227,11078 9254,11078 9254,11160 C 9254,11165 9253,11169 9251,11173 9248,11177 9245,11181 9241,11183 9237,11185 9232,11186 9227,11186 L 9204,11186 9204,11160 9200,11160 9200,11078 Z M 9139,11134 L 9139,11160 9139,11186 9032,11186 9032,11160 9032,11134 9139,11134 Z M 8966,11134 L 8966,11160 8966,11186 8859,11186 8859,11160 8859,11134 8966,11134 Z M 8793,11134 L 8793,11160 8793,11186 8686,11186 8686,11160 8686,11134 8793,11134 Z M 8620,11134 L 8620,11160 8620,11186 8513,11186 8513,11160 8513,11134 8620,11134 Z M 8447,11134 L 8447,11160 8447,11186 8340,11186 8340,11160 8340,11134 8447,11134 Z M 8274,11134 L 8274,11160 8274,11186 8167,11186 8167,11160 8167,11134 8274,11134 Z M 8102,11134 L 8102,11160 8102,11186 7994,11186 7994,11160 7994,11134 8102,11134 Z M 7929,11134 L 7929,11160 7929,11186 7821,11186 7821,11160 7821,11134 7929,11134 Z M 7756,11134 L 7756,11160 7756,11186 7648,11186 7648,11160 7648,11134 7756,11134 Z M 7583,11134 L 7583,11160 7583,11186 7475,11186 7475,11160 7475,11134 7583,11134 Z M 7410,11134 L 7410,11160 7410,11186 7302,11186 7302,11160 7302,11134 7410,11134 Z M 7237,11134 L 7237,11160 7237,11186 7130,11186 7130,11160 7130,11134 7237,11134 Z M 7064,11134 L 7064,11160 7064,11186 6957,11186 6957,11160 6957,11134 7064,11134 Z M 6891,11134 L 6891,11160 6891,11186 6784,11186 6784,11160 6784,11134 6891,11134 Z M 6718,11134 L 6718,11160 6718,11186 6611,11186 6611,11160 6611,11134 6718,11134 Z M 6545,11134 L 6545,11160 6545,11186 6438,11186 6438,11160 6438,11134 6545,11134 Z M 6373,11134 L 6373,11160 6373,11186 6265,11186 6265,11160 6265,11134 6373,11134 Z M 6200,11134 L 6200,11160 6200,11186 6092,11186 6092,11160 6092,11134 6200,11134 Z M 6027,11134 L 6027,11160 6027,11186 5919,11186 5919,11160 5919,11134 6027,11134 Z M 5854,11134 L 5854,11160 5854,11186 5746,11186 5746,11160 5746,11134 5854,11134 Z M 5681,11134 L 5681,11160 5681,11186 5573,11186 5573,11160 5573,11134 5681,11134 Z M 5508,11134 L 5508,11160 5508,11186 5401,11186 5401,11160 5401,11134 5508,11134 Z M 5335,11134 L 5335,11160 5335,11186 5228,11186 5228,11160 5228,11134 5335,11134 Z M 5162,11134 L 5162,11160 5162,11186 5055,11186 5055,11160 5055,11134 5162,11134 Z M 4989,11134 L 4989,11160 4989,11186 4882,11186 4882,11160 4882,11134 4989,11134 Z M 4816,11134 L 4816,11160 4816,11186 4709,11186 4709,11160 4709,11134 4816,11134 Z M 4643,11134 L 4643,11160 4643,11186 4536,11186 4536,11160 4536,11134 4643,11134 Z M 4471,11134 L 4471,11160 4471,11186 4363,11186 4363,11160 4363,11134 4471,11134 Z M 4298,11134 L 4298,11160 4298,11186 4190,11186 4190,11160 4190,11134 4298,11134 Z M 4125,11134 L 4125,11160 4125,11186 4017,11186 4017,11160 4017,11134 4125,11134 Z M 3952,11134 L 3952,11160 3952,11186 3844,11186 3844,11160 3844,11134 3952,11134 Z M 3779,11134 L 3779,11160 3779,11186 3671,11186 3671,11160 3671,11134 3779,11134 Z M 3606,11134 L 3606,11160 3606,11186 3499,11186 3499,11160 3499,11134 3606,11134 Z M 3433,11134 L 3433,11160 3433,11186 3326,11186 3326,11160 3326,11134 3433,11134 Z M 3260,11134 L 3260,11160 3260,11186 3153,11186 3153,11160 3153,11134 3260,11134 Z M 3087,11134 L 3087,11160 3087,11186 2980,11186 2980,11160 2980,11134 3087,11134 Z M 2914,11134 L 2914,11160 2914,11186 2807,11186 2807,11160 2807,11134 2914,11134 Z M 2741,11134 L 2741,11160 2741,11186 2634,11186 2634,11160 2634,11134 2741,11134 Z M 2569,11134 L 2569,11160 2569,11186 2461,11186 2461,11160 2461,11134 2569,11134 Z"/>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.CustomShape">
+       <g id="id14">
+        <rect class="BoundingBox" stroke="none" fill="none" x="7086" y="3539" width="4194" height="1273"/>
+        <path fill="rgb(114,159,207)" stroke="none" d="M 9183,4810 L 7087,4810 7087,3540 11278,3540 11278,4810 9183,4810 Z"/>
+        <path fill="none" stroke="rgb(52,101,164)" d="M 9183,4810 L 7087,4810 7087,3540 11278,3540 11278,4810 9183,4810 Z"/>
+        <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="8218" y="4078"><tspan fill="rgb(0,0,0)" stroke="none">PCEPLIB</tspan></tspan></tspan><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="7900" y="4590"><tspan fill="rgb(0,0,0)" stroke="none">INTERFACE</tspan></tspan></tspan></text>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.LineShape">
+       <g id="id15">
+        <rect class="BoundingBox" stroke="none" fill="none" x="1665" y="6105" width="2033" height="205"/>
+        <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 1956,6207 L 3406,6207"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 1665,6207 L 1970,6309 1970,6106 1665,6207 Z"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 3697,6207 L 3393,6106 3393,6309 3697,6207 Z"/>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.LineShape">
+       <g id="id16">
+        <rect class="BoundingBox" stroke="none" fill="none" x="1665" y="5470" width="2033" height="205"/>
+        <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 1956,5572 L 3406,5572"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 1665,5572 L 1970,5674 1970,5471 1665,5572 Z"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 3697,5572 L 3393,5471 3393,5674 3697,5572 Z"/>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.CustomShape">
+       <g id="id17">
+        <rect class="BoundingBox" stroke="none" fill="none" x="4584" y="9553" width="9528" height="1146"/>
+        <path fill="rgb(114,159,207)" stroke="none" d="M 9348,10697 L 4585,10697 4585,9554 14110,9554 14110,10697 9348,10697 Z"/>
+        <path fill="none" stroke="rgb(52,101,164)" d="M 9348,10697 L 4585,10697 4585,9554 14110,9554 14110,10697 9348,10697 Z"/>
+        <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="7786" y="10285"><tspan fill="rgb(0,0,0)" stroke="none">CONTROLLER</tspan></tspan></tspan></text>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.TextShape">
+       <g id="id18">
+        <rect class="BoundingBox" stroke="none" fill="none" x="6491" y="9448" width="2383" height="570"/>
+        <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="6741" y="9831"><tspan fill="rgb(0,0,0)" stroke="none">pcep_ctrl_XXX</tspan></tspan></tspan></text>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.TextShape">
+       <g id="id19">
+        <rect class="BoundingBox" stroke="none" fill="none" x="9920" y="9448" width="2802" height="570"/>
+        <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="10170" y="9831"><tspan fill="rgb(0,0,0)" stroke="none">pcep_thread_XXX</tspan></tspan></tspan></text>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.LineShape">
+       <g id="id20">
+        <rect class="BoundingBox" stroke="none" fill="none" x="5953" y="8366" width="1682" height="1271"/>
+        <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 6185,8541 L 7402,9461"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 5953,8366 L 6135,8631 6257,8469 5953,8366 Z"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 7634,9636 L 7452,9371 7330,9533 7634,9636 Z"/>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.LineShape">
+       <g id="id21">
+        <rect class="BoundingBox" stroke="none" fill="none" x="5953" y="6207" width="2287" height="3430"/>
+        <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 6114,6449 L 8078,9394"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 5953,6207 L 6037,6517 6206,6404 5953,6207 Z"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 8239,9636 L 8155,9326 7986,9439 8239,9636 Z"/>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.LineShape">
+       <g id="id22">
+        <rect class="BoundingBox" stroke="none" fill="none" x="5953" y="4683" width="1652" height="763"/>
+        <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 6217,5323 L 7340,4805"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 5953,5445 L 6272,5410 6187,5225 5953,5445 Z"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 7604,4683 L 7285,4718 7370,4903 7604,4683 Z"/>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.LineShape">
+       <g id="id23">
+        <rect class="BoundingBox" stroke="none" fill="none" x="5953" y="4683" width="2287" height="3049"/>
+        <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 6128,7498 L 8064,4916"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 5953,7731 L 6217,7548 6054,7427 5953,7731 Z"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 8239,4683 L 7975,4866 8138,4988 8239,4683 Z"/>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.LineShape">
+       <g id="id24">
+        <rect class="BoundingBox" stroke="none" fill="none" x="8772" y="1635" width="205" height="2033"/>
+        <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 8874,3376 L 8874,1926"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 8874,3667 L 8976,3363 8773,3363 8874,3667 Z"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 8874,1635 L 8773,1940 8976,1940 8874,1635 Z"/>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.TextShape">
+       <g id="id25">
+        <rect class="BoundingBox" stroke="none" fill="none" x="8347" y="1127" width="1925" height="570"/>
+        <text class="TextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="282px" font-weight="400"><tspan class="TextPosition" x="8597" y="1510"><tspan fill="rgb(0,0,0)" stroke="none">pceplib API</tspan></tspan></tspan></text>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.LineShape">
+       <g id="id26">
+        <rect class="BoundingBox" stroke="none" fill="none" x="11033" y="4683" width="1779" height="1525"/>
+        <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 11254,4872 L 12590,6018"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 11033,4683 L 11198,4958 11330,4804 11033,4683 Z"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 12811,6207 L 12646,5932 12514,6086 12811,6207 Z"/>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.LineShape">
+       <g id="id27">
+        <rect class="BoundingBox" stroke="none" fill="none" x="11063" y="7223" width="1749" height="2414"/>
+        <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 11234,9400 L 12640,7459"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 11063,9636 L 11324,9449 11159,9330 11063,9636 Z"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 12811,7223 L 12550,7410 12715,7529 12811,7223 Z"/>
+       </g>
+      </g>
+      <g class="com.sun.star.drawing.LineShape">
+       <g id="id28">
+        <rect class="BoundingBox" stroke="none" fill="none" x="9534" y="1635" width="205" height="2033"/>
+        <path fill="none" stroke="rgb(102,102,102)" stroke-width="35" stroke-linejoin="round" d="M 9636,3376 L 9636,1926"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 9636,3667 L 9738,3363 9535,3363 9636,3667 Z"/>
+        <path fill="rgb(102,102,102)" stroke="none" d="M 9636,1635 L 9535,1940 9738,1940 9636,1635 Z"/>
+       </g>
+      </g>
+     </g>
+    </g>
+   </g>
+  </g>
+ </g>
+</svg>
\ No newline at end of file
index d46550d9745c7d7065da5e4c49378813fb3fe2b7..62d50d5d655bc1a8409d1da8c2547c01e50ec7bd 100644 (file)
@@ -34,27 +34,18 @@ Configuration of *babeld* is done in its configuration file
 Babel configuration
 ===================
 
-.. index::
-   single: router babel
-   single: no router babel
-
+.. index:: router babel
 .. clicmd:: [no] router babel
 
    Enable or disable Babel routing.
 
-.. index::
-   single: babel resend-delay (20-655340)
-   single: no babel resend-delay [(20-655340)]
-
+.. index:: babel resend-delay (20-655340)
 .. clicmd:: [no] babel resend-delay (20-655340)
 
    Specifies the time after which important messages are resent when
    avoiding a black-hole. The default is 2000 ms.
 
-.. index::
-   single: babel diversity
-   single: no babel diversity
-
+.. index:: babel diversity
 .. clicmd:: [no] babel diversity
 
    Enable or disable routing using radio frequency diversity.  This is
@@ -72,11 +63,8 @@ Babel configuration
    no role in route selection; you will probably want to set that to 128
    or less on nodes with multiple independent radios.
 
-.. index::
-   single: network IFNAME
-   single: no network IFNAME
-
-.. clicmd:: no network IFNAME
+.. index:: network IFNAME
+.. clicmd:: [no] network IFNAME
 
    Enable or disable Babel on the given interface.
 
@@ -89,10 +77,7 @@ Babel configuration
    Specifying `wireless` (the default) is always correct, but may
    cause slower convergence and extra routing traffic.
 
-.. index::
-   single: babel split-horizon
-   single: no babel split-horizon
-
+.. index:: babel split-horizon
 .. clicmd:: [no] babel split-horizon
 
    Specifies whether to perform split-horizon on the interface.  Specifying
@@ -120,10 +105,7 @@ Babel configuration
    Babel makes extensive use of triggered updates, this can be set to fairly
    high values on links with little packet loss.  The default is 20000 ms.
 
-.. index::
-   single: babel channel (1-254)
-   single: babel channel interfering
-   single: babel channel noninterfering
+.. index:: babel channel
 
 .. clicmd:: babel channel (1-254)
 .. clicmd:: babel channel interfering
@@ -185,9 +167,7 @@ Babel configuration
    when the RTT is higher or equal than rtt-max.  The default is 0, which
    effectively disables the use of a RTT-based cost.
 
-.. index::
-   single: babel enable-timestamps
-   single: no babel enable-timestamps
+.. index:: babel enable-timestamps
 
 .. clicmd:: [no] babel enable-timestamps
 
@@ -216,9 +196,7 @@ Babel configuration
 Babel redistribution
 ====================
 
-.. index::
-   single: redistribute <ipv4|ipv6> KIND
-   single: no redistribute <ipv4|ipv6> KIND
+.. index:: redistribute <ipv4|ipv6> KIND
 
 .. clicmd:: [no] redistribute <ipv4|ipv6> KIND
 
index 7a450bec53a193190d7466c032fee3705208d8a8..1ca3ca3cf2ee5d24f2816c13d4a0bfbccc91e105 100644 (file)
@@ -65,28 +65,19 @@ Basic Config Commands
 
    Set hostname of the router.
 
-.. index::
-   single: no password PASSWORD
-   single: password PASSWORD
-
+.. index:: password PASSWORD
 .. clicmd:: [no] password PASSWORD
 
    Set password for vty interface. The ``no`` form of the command deletes the
    password. If there is no password, a vty won't accept connections.
 
-.. index::
-   single: no enable password PASSWORD
-   single: enable password PASSWORD
-
+.. index:: enable password PASSWORD
 .. clicmd:: [no] enable password PASSWORD
 
    Set enable password. The ``no`` form of the command deletes the enable
    password.
 
-.. index::
-   single: no log trap [LEVEL]
-   single: log trap LEVEL
-
+.. index:: log trap LEVEL
 .. clicmd:: [no] log trap LEVEL
 
    These commands are deprecated and are present only for historical
@@ -97,9 +88,7 @@ Basic Config Commands
    future logging commands to debugging, but it does not change the logging
    level of existing logging destinations.
 
-.. index::
-   single: no log stdout [LEVEL]
-   single: log stdout [LEVEL]
+.. index:: log stdout [LEVEL]
 
 .. clicmd:: [no] log stdout LEVEL
 
@@ -120,10 +109,7 @@ Basic Config Commands
       terminal output.  Use a log file and ``tail -f`` if this rare chance is
       inacceptable to your setup.
 
-.. index::
-   single: no log file [FILENAME [LEVEL]]
-   single: log file FILENAME [LEVEL]
-
+.. index:: log file FILENAME [LEVEL]
 .. clicmd:: [no] log file [FILENAME [LEVEL]]
 
    If you want to log into a file, please specify ``filename`` as
@@ -138,10 +124,7 @@ Basic Config Commands
    deprecated ``log trap`` command) will be used. The ``no`` form of the command
    disables logging to a file.
 
-.. index::
-   single: no log syslog [LEVEL]
-   single: log syslog [LEVEL]
-
+.. index:: log syslog [LEVEL]
 .. clicmd:: [no] log syslog [LEVEL]
 
    Enable logging output to syslog. If the optional second argument specifying
@@ -149,10 +132,7 @@ Basic Config Commands
    debugging, but can be changed using the deprecated ``log trap`` command) will
    be used. The ``no`` form of the command disables logging to syslog.
 
-.. index::
-   single: no log monitor [LEVEL]
-   single: log monitor [LEVEL]
-
+.. index:: log monitor [LEVEL]
 .. clicmd:: [no] log monitor [LEVEL]
 
    Enable logging output to vty terminals that have enabled logging using the
@@ -163,20 +143,14 @@ Basic Config Commands
    level (typically debugging) will be used. The ``no`` form of the command
    disables logging to terminal monitors.
 
-.. index::
-   single: no log facility [FACILITY]
-   single: log facility [FACILITY]
-
+.. index:: log facility [FACILITY]
 .. clicmd:: [no] log facility [FACILITY]
 
    This command changes the facility used in syslog messages. The default
    facility is ``daemon``. The ``no`` form of the command resets the facility
    to the default ``daemon`` facility.
 
-.. index::
-   single: no log record-priority
-   single: log record-priority
-
+.. index:: log record-priority
 .. clicmd:: [no] log record-priority
 
    To include the severity in all messages logged to a file, to stdout, or to
@@ -187,10 +161,7 @@ Basic Config Commands
    versions of syslogd can be configured to include the facility and
    level in the messages emitted.
 
-.. index::
-   single: log timestamp precision (0-6)
-   single: [no] log timestamp precision (0-6)
-
+.. index:: log timestamp precision (0-6)
 .. clicmd:: [no] log timestamp precision [(0-6)]
 
    This command sets the precision of log message timestamps to the given
@@ -206,7 +177,7 @@ Basic Config Commands
    In this example, the precision is set to provide timestamps with
    millisecond accuracy.
 
-.. index:: [no] log commands
+.. index:: log commands
 .. clicmd:: [no] log commands
 
    This command enables the logging of all commands typed by a user to all
@@ -215,10 +186,7 @@ Basic Config Commands
    is used to start the daemon then this command is turned on by default
    and cannot be turned off and the [no] form of the command is dissallowed.
 
-.. index::
-   single: no log-filter WORD [DAEMON]
-   single: log-filter WORD [DAEMON]
-
+.. index:: log-filter WORD [DAEMON]
 .. clicmd:: [no] log-filter WORD [DAEMON]
 
    This command forces logs to be filtered on a specific string. A log message
@@ -275,7 +243,7 @@ Basic Config Commands
 
    Set motd string from an input.
 
-.. index:: no banner motd
+.. index:: banner motd
 .. clicmd:: no banner motd
 
    No motd banner string will be printed.
@@ -288,7 +256,7 @@ Basic Config Commands
    used for timeout value in seconds. Default timeout value is 10 minutes.
    When timeout value is zero, it means no timeout.
 
-.. index:: no exec-timeout
+.. index:: exec-timeout
 .. clicmd:: no exec-timeout
 
    Do not perform timeout at all. This command is as same as
@@ -581,6 +549,11 @@ Terminal Mode Commands
    When executing this command from ``vtysh``, each of the daemons' memory
    usage is printed sequentially.
 
+.. index:: show history
+.. clicmd:: show history
+
+   Dump the vtysh cli history.
+
 .. index:: logmsg LEVEL MESSAGE
 .. clicmd:: logmsg LEVEL MESSAGE
 
@@ -712,6 +685,12 @@ These options apply to all |PACKAGE_NAME| daemons.
 
    Enable the transactional CLI mode.
 
+.. option:: --limit-fds <number>
+
+   Limit the number of file descriptors that will be used internally
+   by the FRR daemons. By default, the daemons use the system ulimit
+   value.
+
 .. _loadable-module-support:
 
 Loadable Module Support
index 86b0c280020aaedb0db4391a5b90140f690548fe..6c83ffa19afecc8ad7c87e455fc9f74db9c04582 100644 (file)
@@ -50,6 +50,40 @@ may also be specified (:ref:`common-invocation-options`).
    This option overrides the location addition that the -N option provides
    to the bfdd.sock
 
+.. option:: --dplaneaddr <type>:<address>[<:port>]
+
+   Configure the distributed BFD data plane listening socket bind address.
+
+   One would expect the data plane to run in the same machine as FRR, so
+   the suggested configuration would be:
+
+      --dplaneaddr unix:/var/run/frr/bfdd_dplane.sock
+
+   Or using IPv4:
+
+      --dplaneaddr ipv4:127.0.0.1
+
+   Or using IPv6:
+
+      --dplaneaddr ipv6:[::1]
+
+   It is also possible to specify a port (for IPv4/IPv6 only):
+
+     --dplaneaddr ipv6:[::1]:50701
+
+   (if ommited the default port is ``50700``).
+
+   It is also possible to operate in client mode (instead of listening for
+   connections). To connect to a data plane server append the letter 'c' to
+   the protocol, example:
+
+     --dplaneaddr ipv4c:127.0.0.1
+
+.. note::
+
+   When using UNIX sockets don't forget to check the file permissions
+   before attempting to use it.
+
 
 .. _bfd-commands:
 
@@ -79,7 +113,7 @@ BFDd Commands
 
    `vrf` selects which domain we want to use.
 
-.. index:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrf_name}]
+.. index:: peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrf_name}]
 .. clicmd:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrf_name}]
 
     Stops and removes the selected peer.
@@ -91,7 +125,7 @@ BFDd Commands
    Creates a peer profile that can be configured in multiple peers.
 
 
-.. index:: no profile WORD
+.. index:: profile WORD
 .. clicmd:: no profile WORD
 
    Deletes a peer profile. Any peer using the profile will have their
@@ -113,6 +147,12 @@ BFDd Commands
 
     Show all configured BFD peers information and current status in brief.
 
+.. index:: show bfd distributed
+.. clicmd:: show bfd distributed
+
+   Show the BFD data plane (distributed BFD) statistics.
+
+
 .. _bfd-peer-config:
 
 Peer / Profile Configuration
@@ -151,7 +191,7 @@ BFD peers and profiles share the same BFD session configuration commands.
    Configures the minimal echo receive transmission interval that this
    system is capable of handling.
 
-.. index:: [no] echo-mode
+.. index:: echo-mode
 .. clicmd:: [no] echo-mode
 
    Enables or disables the echo transmission mode. This mode is disabled
@@ -164,14 +204,14 @@ BFD peers and profiles share the same BFD session configuration commands.
    Echo mode is not supported on multi-hop setups (see :rfc:`5883`
    section 3).
 
-.. index:: [no] shutdown
+.. index:: shutdown
 .. clicmd:: [no] shutdown
 
    Enables or disables the peer. When the peer is disabled an
    'administrative down' message is sent to the remote peer.
 
 
-.. index:: [no] passive-mode
+.. index:: passive-mode
 .. clicmd:: [no] passive-mode
 
    Mark session as passive: a passive session will not attempt to start
@@ -184,7 +224,7 @@ BFD peers and profiles share the same BFD session configuration commands.
 
    The default is active-mode (or ``no passive-mode``).
 
-.. index:: [no] minimum-ttl (1-254)
+.. index:: minimum-ttl (1-254)
 .. clicmd:: [no] minimum-ttl (1-254)
 
    For multi hop sessions only: configure the minimum expected TTL for
@@ -238,7 +278,7 @@ The following commands are available inside the BGP configuration node.
    the connection with its neighbor and, when it goes back up, notify
    BGP to try to connect to it.
 
-.. index:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd
+.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd
 .. clicmd:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd
 
    Removes any notification registration for this neighbor.
@@ -253,7 +293,7 @@ The following commands are available inside the BGP configuration node.
    This is the case when graceful restart is enabled, and it is wished to
    ignore the BD event while waiting for the remote router to restart.
 
-.. index:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure
+.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure
 .. clicmd:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure
 
    Disallow to write CBIT independence in BFD outgoing packets. Also disallow
@@ -267,7 +307,7 @@ The following commands are available inside the BGP configuration node.
    BFD profile to the sessions it creates or that already exist.
 
 
-.. index:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile BFDPROF
+.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile BFDPROF
 .. clicmd:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile BFDPROF
 
    Removes the BFD profile configuration from peer session(s).
@@ -287,7 +327,7 @@ The following commands are available inside the interface configuration node.
    a new neighbor is found a BFD peer is created to monitor the link
    status for fast convergence.
 
-.. index:: no isis bfd
+.. index:: isis bfd
 .. clicmd:: no isis bfd
 
    Removes any notification registration for this interface peers.
@@ -301,7 +341,7 @@ The following commands are available inside the interface configuration node.
 
    Use a BFD profile BFDPROF as provided in the BFD configuration.
 
-.. index:: no isis bfd profile BFDPROF
+.. index:: isis bfd profile BFDPROF
 .. clicmd:: no isis bfd profile BFDPROF
 
    Removes any BFD profile if present.
@@ -320,7 +360,7 @@ The following commands are available inside the interface configuration node.
    a new neighbor is found a BFD peer is created to monitor the link
    status for fast convergence.
 
-.. index:: no ip ospf bfd
+.. index:: ip ospf bfd
 .. clicmd:: no ip ospf bfd
 
    Removes any notification registration for this interface peers.
@@ -340,7 +380,7 @@ The following commands are available inside the interface configuration node.
    a new neighbor is found a BFD peer is created to monitor the link
    status for fast convergence.
 
-.. index:: no ipv6 ospf6 bfd
+.. index:: ipv6 ospf6 bfd
 .. clicmd:: no ipv6 ospf6 bfd
 
    Removes any notification registration for this interface peers.
@@ -360,7 +400,7 @@ The following commands are available inside the interface configuration node.
    a new neighbor is found a BFD peer is created to monitor the link
    status for fast convergence.
 
-.. index:: no ip pim bfd
+.. index:: ip pim bfd
 .. clicmd:: no ip pim bfd
 
    Removes any notification registration for this interface peers.
@@ -603,6 +643,68 @@ You can also clear packet counters per session with the following commands, only
                 Session down events: 0
                 Zebra notifications: 4
 
+
+.. _bfd-distributed:
+
+Distributed BFD
+===============
+
+The distributed BFD is the separation of the BFD protocol control plane from
+the data plane. FRR implements its own BFD data plane protocol so vendors can
+study and include it in their own software/hardware without having to modify
+the FRR source code. The protocol definitions can be found at
+``bfdd/bfddp_packet.h`` header (or the installed
+``/usr/include/frr/bfdd/bfddp_packet.h``).
+
+To use this feature the BFD daemon needs to be started using the command line
+option :option:`--dplaneaddr`. When operating using this option the BFD daemon
+will not attempt to establish BFD sessions, but it will offload all its work to
+the data plane that is (or will be) connected. Data plane reconnection is also
+supported.
+
+The BFD data plane will be responsible for:
+
+* Sending/receiving the BFD protocol control/echo packets
+
+* Notifying BFD sessions state changes
+
+* Keeping the number of packets/bytes received/transmitted per session
+
+
+The FRR BFD daemon will be responsible for:
+
+* Adding/updating BFD session settings
+
+* Asking for BFD session counters
+
+* Redistributing the state changes to the integrated protocols (``bgpd``,
+  ``ospfd`` etc...)
+
+
+BFD daemon will also keep record of data plane communication statistics with
+the command :clicmd:`show bfd distributed`.
+
+Sample output:
+
+::
+
+   frr# show bfd distributed
+               Data plane
+               ==========
+          File descriptor: 16
+              Input bytes: 1296
+         Input bytes peak: 72
+           Input messages: 42
+      Input current usage: 0
+             Output bytes: 568
+        Output bytes peak: 136
+          Output messages: 19
+       Output full events: 0
+     Output current usage: 0
+
+
+.. _bfd-debugging:
+
 Debugging
 =========
 
@@ -619,19 +721,29 @@ sure you have `debugging` level enabled:
 You may also fine tune the debug messages by selecting one or more of the
 debug levels:
 
-.. index:: [no] debug bfd network
+.. index:: debug bfd distributed
+.. clicmd:: [no] debug bfd distributed
+
+   Toggle BFD data plane (distributed BFD) debugging.
+
+   Activates the following debug messages:
+
+   * Data plane received / send messages
+   * Connection events
+
+.. index:: debug bfd network
 .. clicmd:: [no] debug bfd network
 
    Toggle network events: show messages about socket failures and unexpected
    BFD messages that may not belong to registered peers.
 
-.. index:: [no] debug bfd peer
+.. index:: debug bfd peer
 .. clicmd:: [no] debug bfd peer
 
    Toggle peer event log messages: show messages about peer creation/removal
    and state changes.
 
-.. index:: [no] debug bfd zebra
+.. index:: debug bfd zebra
 .. clicmd:: [no] debug bfd zebra
 
    Toggle zebra message events: show messages about interfaces, local
index 0a562e1edf1dded226362647515c6e27f47b06d2..e609761e1c7071f30fb94fa57c0a4ae021cc3569 100644 (file)
@@ -31,9 +31,22 @@ be specified (:ref:`common-invocation-options`).
 
 .. option:: -l, --listenon
 
-   Specify a specific IP address for bgpd to listen on, rather than its default
+   Specify specific IP addresses for bgpd to listen on, rather than its default
    of ``0.0.0.0`` / ``::``. This can be useful to constrain bgpd to an internal
-   address, or to run multiple bgpd processes on one host.
+   address, or to run multiple bgpd processes on one host. Multiple addresses
+   can be specified.
+
+   In the following example, bgpd is started listening for connections on the
+   addresses 100.0.1.2 and fd00::2:2. The options -d (runs in daemon mode) and
+   -f (uses specific configuration file) are also used in this example as we
+   are likely to run multiple bgpd instances, each one with different
+   configurations, when using -l option.
+
+   Note that this option implies the --no_kernel option, and no learned routes will be installed into the linux kernel.
+
+.. code-block:: shell
+
+   # /usr/lib/frr/bgpd -d -f /some-folder/bgpd.conf -l 100.0.1.2 -l fd00::2:2
 
 .. option:: -n, --no_kernel
 
@@ -245,7 +258,7 @@ internal or external.
    Enable a BGP protocol process with the specified ASN. After
    this statement you can input any `BGP Commands`.
 
-.. index:: no router bgp ASN
+.. index:: router bgp ASN
 .. clicmd:: no router bgp ASN
 
    Destroy a BGP protocol process with the specified ASN.
@@ -418,7 +431,7 @@ Administrative Distance Metrics
 Require policy on EBGP
 -------------------------------
 
-.. index:: [no] bgp ebgp-requires-policy
+.. index:: bgp ebgp-requires-policy
 .. clicmd:: [no] bgp ebgp-requires-policy
 
    This command requires incoming and outgoing filters to be applied
@@ -447,15 +460,26 @@ Require policy on EBGP
 Reject routes with AS_SET or AS_CONFED_SET types
 ------------------------------------------------
 
-.. index:: [no] bgp reject-as-sets
+.. index:: bgp reject-as-sets
 .. clicmd:: [no] bgp reject-as-sets
 
    This command enables rejection of incoming and outgoing routes having AS_SET or AS_CONFED_SET type.
 
+Suppress duplicate updates
+--------------------------
+
+.. index:: bgp suppress-duplicates
+.. clicmd:: [no] bgp suppress-duplicates
+
+   For example, BGP routers can generate multiple identical announcements with
+   empty community attributes if stripped at egress. This is an undesired behavior.
+   Suppress duplicate updates if the route actually not changed.
+   Default: enabled.
+
 Disable checking if nexthop is connected on EBGP sessions
 ---------------------------------------------------------
 
-.. index:: [no] bgp disable-ebgp-connected-route-check
+.. index:: bgp disable-ebgp-connected-route-check
 .. clicmd:: [no] bgp disable-ebgp-connected-route-check
 
    This command is used to disable the connection verification process for EBGP peering sessions
@@ -467,28 +491,57 @@ Disable checking if nexthop is connected on EBGP sessions
 Route Flap Dampening
 --------------------
 
-.. clicmd:: bgp dampening (1-45) (1-20000) (1-20000) (1-255)
+.. index:: [no] bgp dampening [(1-45) [(1-20000) (1-20000) (1-255)]]
+.. clicmd:: [no] bgp dampening [(1-45) [(1-20000) (1-20000) (1-255)]]
+
+   This command enables (with optionally specified dampening parameters) or
+   disables route-flap dampening for all routes of a BGP instance.
+
+.. index:: [no] neighbor PEER dampening [(1-45) [(1-20000) (1-20000) (1-255)]]
+.. clicmd:: [no] neighbor PEER dampening [(1-45) [(1-20000) (1-20000) (1-255)]]
+
+   This command enables (with optionally specified dampening parameters) or
+   disables route-flap dampening for all routes learned from a BGP peer.
+
+.. index:: [no] neighbor GROUP dampening [(1-45) [(1-20000) (1-20000) (1-255)]]
+.. clicmd:: [no] neighbor GROUP dampening [(1-45) [(1-20000) (1-20000) (1-255)]]
 
-   This command enables BGP route-flap dampening and specifies dampening parameters.
+   This command enables (with optionally specified dampening parameters) or
+   disables route-flap dampening for all routes learned from peers of a peer
+   group.
 
    half-life
-      Half-life time for the penalty
+      Half-life time for the penalty in minutes (default value: 15).
 
    reuse-threshold
-      Value to start reusing a route
+      Value to start reusing a route (default value: 750).
 
    suppress-threshold
-      Value to start suppressing a route
+      Value to start suppressing a route (default value: 2000).
 
    max-suppress
-      Maximum duration to suppress a stable route
+      Maximum duration to suppress a stable route in minutes (default value:
+      60).
 
    The route-flap damping algorithm is compatible with :rfc:`2439`. The use of
-   this command is not recommended nowadays.
+   these commands is not recommended nowadays.
 
    At the moment, route-flap dampening is not working per VRF and is working only
    for IPv4 unicast and multicast.
 
+   With different parameter sets configurable for BGP instances, peer groups and
+   peers, the active dampening profile for a route is chosen on the fly,
+   allowing for various changes in configuration (i.e. peer group memberships)
+   during runtime. The parameter sets are taking precedence in the following
+   order:
+
+   1. Peer
+   2. Peer group
+   3. BGP instance
+
+   The negating commands do not allow to exclude a peer/peer group from a peer
+   group/BGP instances configuration.
+
 .. seealso::
    https://www.ripe.net/publications/docs/ripe-378
 
@@ -796,6 +849,38 @@ The following functionality is provided by graceful restart:
  <--------------------------------------------------------------------->
 
 
+.. _bgp-GR-preserve-forwarding-state:
+
+BGP-GR Preserve-Forwarding State
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+BGP OPEN message carrying optional capabilities for Graceful Restart has
+8 bit “Flags for Address Family” for given AFI and SAFI. This field contains
+bit flags relating to routes that were advertised with the given AFI and SAFI.
+
+.. code-block:: frr
+
+   0 1 2 3 4 5 6 7
+   +-+-+-+-+-+-+-+-+
+   |F|   Reserved  |
+   +-+-+-+-+-+-+-+-+
+
+The most significant bit is defined as the Forwarding State (F) bit, which
+can be used to indicate whether the forwarding state for routes that were
+advertised with the given AFI and SAFI has indeed been preserved during the
+previous BGP restart. When set (value 1), the bit indicates that the
+forwarding state has been preserved.
+The remaining bits are reserved and MUST be set to zero by the sender and
+ignored by the receiver.
+
+.. index:: bgp graceful-restart preserve-fw-state
+.. clicmd:: bgp graceful-restart preserve-fw-state
+
+FRR gives us the option to enable/disable the "F" flag using this specific
+vty command. However, it doesn't have the option to enable/disable
+this flag only for specific AFI/SAFI i.e. when this command is used, it
+applied to all the supported AFI/SAFI combinations for this peer.
+
 .. _bgp-end-of-rib-message:
 
 End-of-RIB (EOR) message
@@ -849,6 +934,19 @@ However, it MUST defer route selection for an address family until it either.
 
    This is command, will set the time for which stale routes are kept in RIB.
 
+.. index:: bgp graceful-restart stalepath-time (1-4095)
+.. clicmd:: bgp graceful-restart stalepath-time (1-4095)
+
+   This is command, will set the max time (in seconds) to hold onto
+   restarting peer's stale paths.
+
+   It also controls Enhanced Route-Refresh timer.
+
+   If this command is configured and the router does not receive a Route-Refresh EoRR
+   message, the router removes the stale routes from the BGP table after the timer
+   expires. The stale path timer is started when the router receives a Route-Refresh
+   BoRR message.
+
 .. _bgp-per-peer-graceful-restart:
 
 BGP Per Peer Graceful Restart
@@ -912,7 +1010,7 @@ BGP GR Peer Mode Commands
 Administrative Shutdown
 -----------------------
 
-.. index:: [no] bgp shutdown [message MSG...]
+.. index:: bgp shutdown [message MSG...]
 .. clicmd:: [no] bgp shutdown [message MSG...]
 
    Administrative shutdown of all peers of a bgp instance. Drop all BGP peers,
@@ -948,10 +1046,10 @@ Networks
    routes if they aren't present in their IGP routing tables; `bgpd`
    doesn't care about IGP routes when announcing its routes.
 
-.. index:: no network A.B.C.D/M
+.. index:: network A.B.C.D/M
 .. clicmd:: no network A.B.C.D/M
 
-.. index:: [no] bgp network import-check
+.. index:: bgp network import-check
 .. clicmd:: [no] bgp network import-check
 
    This configuration modifies the behavior of the network statement.
@@ -967,7 +1065,7 @@ Networks
 IPv6 Support
 ------------
 
-.. index:: [no] neighbor A.B.C.D activate
+.. index:: neighbor A.B.C.D activate
 .. clicmd:: [no] neighbor A.B.C.D activate
 
    This configuration modifies whether to enable an address family for a
@@ -985,9 +1083,6 @@ IPv6 Support
    This configuration example says that network 2001:0DB8:5009::/64 will be
    announced and enables the neighbor 2001:0DB8::1 to receive this announcement.
 
-.. index:: [no] bgp default ipv4-unicast
-.. clicmd:: [no] bgp default ipv4-unicast
-
    By default, only the IPv4 unicast address family is announced to all
    neighbors. Using the 'no bgp default ipv4-unicast' configuration overrides
    this default so that all address families need to be enabled explicitly.
@@ -1061,7 +1156,7 @@ Route Aggregation-IPv4 Address Family
    Similar to `summary-only`, but will only suppress more specific routes that
    are matched by the selected route-map.
 
-.. index:: no aggregate-address A.B.C.D/M
+.. index:: aggregate-address A.B.C.D/M
 .. clicmd:: no aggregate-address A.B.C.D/M
 
    This command removes an aggregate address.
@@ -1125,7 +1220,7 @@ Route Aggregation-IPv6 Address Family
    Similar to `summary-only`, but will only suppress more specific routes that
    are matched by the selected route-map.
 
-.. index:: no aggregate-address X:X::X:X/M
+.. index:: aggregate-address X:X::X:X/M
 .. clicmd:: no aggregate-address X:X::X:X/M
 
    This command removes an aggregate address.
@@ -1307,7 +1402,7 @@ Defining Peers
    peers ASN is the same as mine as specified under the :clicmd:`router bgp ASN`
    command the connection will be denied.
 
-.. index:: [no] bgp listen range <A.B.C.D/M|X:X::X:X/M> peer-group PGNAME
+.. index:: bgp listen range <A.B.C.D/M|X:X::X:X/M> peer-group PGNAME
 .. clicmd:: [no] bgp listen range <A.B.C.D/M|X:X::X:X/M> peer-group PGNAME
 
    Accept connections from any peers in the specified prefix. Configuration
@@ -1331,7 +1426,7 @@ Defining Peers
    ``net.core.optmem_max`` to allow the kernel to allocate the necessary option
    memory.
 
-.. index:: [no] coalesce-time (0-4294967295)
+.. index:: coalesce-time (0-4294967295)
 .. clicmd:: [no] coalesce-time (0-4294967295)
 
    The time in milliseconds that BGP will delay before deciding what peers
@@ -1343,7 +1438,7 @@ Defining Peers
 Configuring Peers
 ^^^^^^^^^^^^^^^^^
 
-.. index:: [no] neighbor PEER shutdown [message MSG...] [rtt (1-65535) [count (1-255)]]
+.. index:: neighbor PEER shutdown [message MSG...] [rtt (1-65535) [count (1-255)]]
 .. clicmd:: [no] neighbor PEER shutdown [message MSG...] [rtt (1-65535) [count (1-255)]]
 
    Shutdown the peer. We can delete the neighbor's configuration by
@@ -1359,13 +1454,13 @@ Configuring Peers
    Additional ``count`` parameter is the number of keepalive messages to count
    before shutdown the peer if round-trip-time becomes higher than defined.
 
-.. index:: [no] neighbor PEER disable-connected-check
+.. index:: neighbor PEER disable-connected-check
 .. clicmd:: [no] neighbor PEER disable-connected-check
 
    Allow peerings between directly connected eBGP peers using loopback
    addresses.
 
-.. index:: [no] neighbor PEER ebgp-multihop
+.. index:: neighbor PEER ebgp-multihop
 .. clicmd:: [no] neighbor PEER ebgp-multihop
 
    Specifying ``ebgp-multihop`` allows sessions with eBGP neighbors to
@@ -1373,12 +1468,12 @@ Configuring Peers
    directly connected and this knob is not enabled, the session will not
    establish.
 
-.. index:: [no] neighbor PEER description ...
+.. index:: neighbor PEER description ...
 .. clicmd:: [no] neighbor PEER description ...
 
    Set description of the peer.
 
-.. index:: [no] neighbor PEER version VERSION
+.. index:: neighbor PEER version VERSION
 .. clicmd:: [no] neighbor PEER version VERSION
 
    Set up the neighbor's BGP version. `version` can be `4`, `4+` or `4-`. BGP
@@ -1388,7 +1483,7 @@ Configuring Peers
    revision 00's Multiprotocol Extensions for BGP-4. Some routing software is
    still using this version.
 
-.. index:: [no] neighbor PEER interface IFNAME
+.. index:: neighbor PEER interface IFNAME
 .. clicmd:: [no] neighbor PEER interface IFNAME
 
    When you connect to a BGP peer over an IPv6 link-local address, you have to
@@ -1399,7 +1494,7 @@ Configuring Peers
    This command is deprecated and may be removed in a future release. Its use
    should be avoided.
 
-.. index:: [no] neighbor PEER next-hop-self [all]
+.. index:: neighbor PEER next-hop-self [all]
 .. clicmd:: [no] neighbor PEER next-hop-self [all]
 
    This command specifies an announced route's nexthop as being equivalent to
@@ -1415,7 +1510,7 @@ Configuring Peers
    configurations, as the route-map directive to leave the next-hop unchanged
    is only available for ipv4.
 
-.. index:: [no] neighbor PEER update-source <IFNAME|ADDRESS>
+.. index:: neighbor PEER update-source <IFNAME|ADDRESS>
 .. clicmd:: [no] neighbor PEER update-source <IFNAME|ADDRESS>
 
    Specify the IPv4 source address to use for the :abbr:`BGP` session to this
@@ -1430,7 +1525,7 @@ Configuring Peers
        neighbor bar update-source lo0
 
 
-.. index:: [no] neighbor PEER default-originate
+.. index:: neighbor PEER default-originate
 .. clicmd:: [no] neighbor PEER default-originate
 
    *bgpd*'s default is to not announce the default route (0.0.0.0/0) even if it
@@ -1440,7 +1535,7 @@ Configuring Peers
 .. index:: neighbor PEER port PORT
 .. clicmd:: neighbor PEER port PORT
 
-.. index:: [no] neighbor PEER password PASSWORD
+.. index:: neighbor PEER password PASSWORD
 .. clicmd:: [no] neighbor PEER password PASSWORD
 
    Set a MD5 password to be used with the tcp socket that is being used
@@ -1452,12 +1547,12 @@ Configuring Peers
 .. index:: neighbor PEER send-community
 .. clicmd:: neighbor PEER send-community
 
-.. index:: [no] neighbor PEER weight WEIGHT
+.. index:: neighbor PEER weight WEIGHT
 .. clicmd:: [no] neighbor PEER weight WEIGHT
 
    This command specifies a default `weight` value for the neighbor's routes.
 
-.. index:: [no] neighbor PEER maximum-prefix NUMBER [force]
+.. index:: neighbor PEER maximum-prefix NUMBER [force]
 .. clicmd:: [no] neighbor PEER maximum-prefix NUMBER [force]
 
    Sets a maximum number of prefixes we can receive from a given peer. If this
@@ -1475,7 +1570,7 @@ Configuring Peers
    but you want maximum-prefix to act on ALL (including filtered) prefixes. This
    option requires `soft-reconfiguration inbound` to be enabled for the peer.
 
-.. index:: [no] neighbor PEER maximum-prefix-out NUMBER
+.. index:: neighbor PEER maximum-prefix-out NUMBER
 .. clicmd:: [no] neighbor PEER maximum-prefix-out NUMBER
 
    Sets a maximum number of prefixes we can send to a given peer.
@@ -1483,7 +1578,7 @@ Configuring Peers
    Since sent prefix count is managed by update-groups, this option
    creates a separate update-group for outgoing updates.
 
-.. index:: [no] neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as]
+.. index:: neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as]
 .. clicmd:: [no] neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as]
 
    Specify an alternate AS for this BGP process when interacting with the
@@ -1502,7 +1597,7 @@ Configuring Peers
 
    This command is only allowed for eBGP peers.
 
-.. index:: [no] neighbor <A.B.C.D|X:X::X:X|WORD> as-override
+.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> as-override
 .. clicmd:: [no] neighbor <A.B.C.D|X:X::X:X|WORD> as-override
 
    Override AS number of the originating router with the local AS number.
@@ -1515,7 +1610,7 @@ Configuring Peers
 
    This command is only allowed for eBGP peers.
 
-.. index:: [no] neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>]
+.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>]
 .. clicmd:: [no] neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>]
 
    Accept incoming routes with AS path containing AS number with the same value
@@ -1533,19 +1628,19 @@ Configuring Peers
 
    This command is only allowed for eBGP peers.
 
-.. index:: [no] neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths
+.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths
 .. clicmd:: [no] neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths
 
    Configure BGP to send all known paths to neighbor in order to preserve multi
    path capabilities inside a network.
 
-.. index:: [no] neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS
+.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS
 .. clicmd:: [no] neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS
 
    Configure BGP to send best known paths to neighbor in order to preserve multi
    path capabilities inside a network.
 
-.. index:: [no] neighbor PEER ttl-security hops NUMBER
+.. index:: neighbor PEER ttl-security hops NUMBER
 .. clicmd:: [no] neighbor PEER ttl-security hops NUMBER
 
    This command enforces Generalized TTL Security Mechanism (GTSM), as
@@ -1553,7 +1648,7 @@ Configuring Peers
    specified number of hops away will be allowed to become neighbors. This
    command is mutually exclusive with *ebgp-multihop*.
 
-.. index:: [no] neighbor PEER capability extended-nexthop
+.. index:: neighbor PEER capability extended-nexthop
 .. clicmd:: [no] neighbor PEER capability extended-nexthop
 
    Allow bgp to negotiate the extended-nexthop capability with it's peer.
@@ -1562,7 +1657,7 @@ 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.
 
-.. index:: [no] bgp fast-external-failover
+.. index:: bgp fast-external-failover
 .. clicmd:: [no] bgp fast-external-failover
 
    This command causes bgp to not take down ebgp peers immediately
@@ -1570,33 +1665,42 @@ Configuring Peers
    and will not be displayed as part of a `show run`.  The no form
    of the command turns off this ability.
 
-.. index:: [no] bgp default ipv4-unicast
+.. index:: bgp default ipv4-unicast
 .. clicmd:: [no] bgp default ipv4-unicast
 
    This command allows the user to specify that v4 peering is turned
    on by default or not.  This command defaults to on and is not displayed.
    The `no bgp default ipv4-unicast` form of the command is displayed.
 
-.. index:: [no] bgp default show-hostname
+.. index:: bgp default show-hostname
 .. clicmd:: [no] bgp default show-hostname
 
    This command shows the hostname of the peer in certain BGP commands
    outputs. It's easier to troubleshoot if you have a number of BGP peers.
 
-.. index:: [no] bgp default show-nexthop-hostname
+.. index:: bgp default show-nexthop-hostname
 .. clicmd:: [no] bgp default show-nexthop-hostname
 
    This command shows the hostname of the next-hop in certain BGP commands
    outputs. It's easier to troubleshoot if you have a number of BGP peers
    and a number of routes to check.
 
-.. index:: [no] neighbor PEER advertisement-interval (0-600)
+.. index:: neighbor PEER advertisement-interval (0-600)
 .. clicmd:: [no] neighbor PEER advertisement-interval (0-600)
 
    Setup the minimum route advertisement interval(mrai) for the
    peer in question.  This number is between 0 and 600 seconds,
    with the default advertisement interval being 0.
 
+.. index:: neighbor PEER timers delayopen (1-240)
+.. clicmd:: [no] neighbor PEER timers delayopen (1-240)
+
+   This command allows the user enable the
+   `RFC 4271 <https://tools.ietf.org/html/rfc4271/>` DelayOpenTimer with the
+   specified interval or disable it with the negating command for the peer. By
+   default, the DelayOpenTimer is disabled. The timer interval may be set to a
+   duration of 1 to 240 seconds.
+
 Displaying Information about Peers
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -1635,7 +1739,7 @@ Peer Filtering
    on reflected routes. This option allows the modifications to be reflected as
    well. Once enabled, it affects all reflected routes.
 
-.. index:: [no] neighbor PEER sender-as-path-loop-detection
+.. index:: neighbor PEER sender-as-path-loop-detection
 .. clicmd:: [no] neighbor PEER sender-as-path-loop-detection
 
    Enable the detection of sender side AS path loops and filter the
@@ -1679,7 +1783,7 @@ Capability Negotiation
 .. index:: neighbor PEER strict-capability-match
 .. clicmd:: neighbor PEER strict-capability-match
 
-.. index:: no neighbor PEER strict-capability-match
+.. index:: neighbor PEER strict-capability-match
 .. clicmd:: no neighbor PEER strict-capability-match
 
    Strictly compares remote capabilities and local capabilities. If
@@ -1691,7 +1795,7 @@ Capability Negotiation
    Negotiation. Please use *dont-capability-negotiate* command to disable the
    feature.
 
-.. index:: [no] neighbor PEER dont-capability-negotiate
+.. index:: neighbor PEER dont-capability-negotiate
 .. clicmd:: [no] neighbor PEER dont-capability-negotiate
 
    Suppress sending Capability Negotiation as OPEN message optional parameter
@@ -1715,7 +1819,7 @@ Capability Negotiation
 .. index:: neighbor PEER override-capability
 .. clicmd:: neighbor PEER override-capability
 
-.. index:: no neighbor PEER override-capability
+.. index:: neighbor PEER override-capability
 .. clicmd:: no neighbor PEER override-capability
 
    Override the result of Capability Negotiation with local configuration.
@@ -1733,10 +1837,10 @@ AS path access list is user defined AS path.
 
    This command defines a new AS path access list.
 
-.. index:: no bgp as-path access-list WORD
+.. index:: bgp as-path access-list WORD
 .. clicmd:: no bgp as-path access-list WORD
 
-.. index:: no bgp as-path access-list WORD permit|deny LINE
+.. index:: bgp as-path access-list WORD permit|deny LINE
 .. clicmd:: no bgp as-path access-list WORD permit|deny LINE
 
 .. _bgp-bogon-filter-example:
@@ -1755,20 +1859,20 @@ Bogon ASN filter policy configuration example
 Using AS Path in Route Map
 --------------------------
 
-.. index:: [no] match as-path WORD
+.. index:: match as-path WORD
 .. clicmd:: [no] match as-path WORD
 
    For a given as-path, WORD, match it on the BGP as-path given for the prefix
    and if it matches do normal route-map actions.  The no form of the command
    removes this match from the route-map.
 
-.. index:: [no] set as-path prepend AS-PATH
+.. index:: set as-path prepend AS-PATH
 .. clicmd:: [no] set as-path prepend AS-PATH
 
    Prepend the given string of AS numbers to the AS_PATH of the BGP path's NLRI.
    The no form of this command removes this set operation from the route-map.
 
-.. index:: [no] set as-path prepend last-as NUM
+.. index:: set as-path prepend last-as NUM
 .. clicmd:: [no] set as-path prepend last-as NUM
 
    Prepend the existing last AS number (the leftmost ASN) to the AS_PATH.
@@ -1948,7 +2052,7 @@ expanded
    for backward compatibility. Use of this feature is not recommended.
 
 
-.. index:: no bgp community-list [standard|expanded] NAME
+.. index:: bgp community-list [standard|expanded] NAME
 .. clicmd:: no bgp community-list [standard|expanded] NAME
 
    Deletes the community list specified by ``NAME``. All community lists share
@@ -2230,13 +2334,13 @@ Extended Community Lists
    expression (:ref:`bgp-regular-expressions`) to match an extended communities
    attribute in BGP updates.
 
-.. index:: no bgp extcommunity-list NAME
+.. index:: bgp extcommunity-list NAME
 .. clicmd:: no bgp extcommunity-list NAME
 
-.. index:: no bgp extcommunity-list standard NAME
+.. index:: bgp extcommunity-list standard NAME
 .. clicmd:: no bgp extcommunity-list standard NAME
 
-.. index:: no bgp extcommunity-list expanded NAME
+.. index:: bgp extcommunity-list expanded NAME
 .. clicmd:: no bgp extcommunity-list expanded NAME
 
    These commands delete extended community lists specified by `name`. All of
@@ -2345,13 +2449,13 @@ Two types of large community lists are supported, namely `standard` and
    lowest to highest.  `line` can also be a regular expression which matches
    this Large Community attribute.
 
-.. index:: no bgp large-community-list NAME
+.. index:: bgp large-community-list NAME
 .. clicmd:: no bgp large-community-list NAME
 
-.. index:: no bgp large-community-list standard NAME
+.. index:: bgp large-community-list standard NAME
 .. clicmd:: no bgp large-community-list standard NAME
 
-.. index:: no bgp large-community-list expanded NAME
+.. index:: bgp large-community-list expanded NAME
 .. clicmd:: no bgp large-community-list expanded NAME
 
    These commands delete Large Community lists specified by `name`. All Large
@@ -2481,7 +2585,7 @@ address-family:
    Specifies the route distinguisher to be added to a route exported from the
    current unicast VRF to VPN.
 
-.. index:: no rd vpn export [AS:NN|IP:nn]
+.. index:: rd vpn export [AS:NN|IP:nn]
 .. clicmd:: no rd vpn export [AS:NN|IP:nn]
 
    Deletes any previously-configured export route distinguisher.
@@ -2497,7 +2601,7 @@ address-family:
    extended community values as described in
    :ref:`bgp-extended-communities-attribute`.
 
-.. index:: no rt vpn import|export|both [RTLIST...]
+.. index:: rt vpn import|export|both [RTLIST...]
 .. clicmd:: no rt vpn import|export|both [RTLIST...]
 
    Deletes any previously-configured import or export route-target list.
@@ -2511,7 +2615,7 @@ address-family:
    is not running, or if this command is not configured, automatic label
    assignment will not complete, which will block corresponding route export.
 
-.. index:: no label vpn export [(0..1048575)|auto]
+.. index:: label vpn export [(0..1048575)|auto]
 .. clicmd:: no label vpn export [(0..1048575)|auto]
 
    Deletes any previously-configured export label.
@@ -2523,7 +2627,7 @@ address-family:
    the current unicast VRF to VPN. If left unspecified, the nexthop will be set
    to 0.0.0.0 or 0:0::0:0 (self).
 
-.. index:: no nexthop vpn export [A.B.C.D|X:X::X:X]
+.. index:: nexthop vpn export [A.B.C.D|X:X::X:X]
 .. clicmd:: no nexthop vpn export [A.B.C.D|X:X::X:X]
 
    Deletes any previously-configured export nexthop.
@@ -2534,7 +2638,7 @@ address-family:
    Specifies an optional route-map to be applied to routes imported or exported
    between the current unicast VRF and VPN.
 
-.. index:: no route-map vpn import|export [MAP]
+.. index:: route-map vpn import|export [MAP]
 .. clicmd:: no route-map vpn import|export [MAP]
 
    Deletes any previously-configured import or export route-map.
@@ -2544,7 +2648,7 @@ address-family:
 
    Enables import or export of routes between the current unicast VRF and VPN.
 
-.. index:: no import|export vpn
+.. index:: import|export vpn
 .. clicmd:: no import|export vpn
 
    Disables import or export of routes between the current unicast VRF and VPN.
@@ -2562,7 +2666,7 @@ address-family:
    The CLI will disallow attempts to configure incompatible leaking
    modes.
 
-.. index:: no import vrf VRFNAME
+.. index:: import vrf VRFNAME
 .. clicmd:: no import vrf VRFNAME
 
    Disables automatic leaking from vrf VRFNAME to the current VRF using
@@ -2618,7 +2722,7 @@ disable the feature via configuration CLI. Once the feature is disable under
 bgp vrf instance or MAC-VLAN interface is not configured, all the routes follow
 the same behavior of using same next-hop and RMAC values.
 
-.. index:: [no] advertise-pip [ip <addr> [mac <addr>]]
+.. index:: advertise-pip [ip <addr> [mac <addr>]]
 .. clicmd:: [no] advertise-pip [ip <addr> [mac <addr>]]
 
 Enables or disables advertise-pip feature, specifiy system-IP and/or system-MAC
@@ -2636,10 +2740,10 @@ Ethernet Segments
 An Ethernet Segment can be configured by specifying a system-MAC and a
 local discriminatior against the bond interface on the PE (via zebra) -
 
-.. index:: [no] evpn mh es-id [(1-16777215)$es_lid]
+.. index:: evpn mh es-id [(1-16777215)$es_lid]
 .. clicmd:: [no] evpn mh es-id [(1-16777215)$es_lid]
 
-.. index:: [no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac]
+.. index:: evpn mh es-sys-mac [X:X:X:X:X:X$mac]
 .. clicmd:: [no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac]
 
 The sys-mac and local discriminator are used for generating a 10-byte,
@@ -2663,7 +2767,7 @@ forward BUM traffic received via the overlay network. This implementation
 uses a preference based DF election specified by draft-ietf-bess-evpn-pref-df.
 The DF preference is configurable per-ES (via zebra) -
 
-.. index:: [no] evpn mh es-df-pref [(1-16777215)$df_pref]
+.. index:: evpn mh es-df-pref [(1-16777215)$df_pref]
 .. clicmd:: [no] evpn mh es-df-pref [(1-16777215)$df_pref]
 
 BUM traffic is rxed via the overlay by all PEs attached to a server but
@@ -2686,14 +2790,14 @@ been introduced for the express purpose of efficient ES failovers.
   On dataplanes that support layer3 nexthop groups the feature can be turned
   on via the following BGP config -
 
-.. index:: [no$no] use-es-l3nhg
+.. index:: use-es-l3nhg
 .. clicmd:: [no$no] use-es-l3nhg
 
 - Local ES (MAC/Neigh) failover via ES-redirect.
   On dataplanes that do not have support for ES-redirect the feature can be
   turned off via the following zebra config -
 
-.. index:: [no$no] evpn mh redirect-off
+.. index:: evpn mh redirect-off
 .. clicmd:: [no$no] evpn mh redirect-off
 
 Uplink/Core tracking
@@ -2703,7 +2807,7 @@ When all the underlay links go down the PE no longer has access to the VxLAN
 protodowned on the PE. A link can be setup for uplink tracking via the
 following zebra configuration -
 
-.. index:: [no] evpn mh uplink
+.. index:: evpn mh uplink
 .. clicmd:: [no] evpn mh uplink
 
 Proxy advertisements
@@ -2715,10 +2819,10 @@ the ES peer (PE2) goes down PE1 continues to advertise hosts learnt from PE2
 for a holdtime during which it attempts to establish local reachability of
 the host. This holdtime is configurable via the following zebra commands -
 
-.. index:: [no$no] evpn mh neigh-holdtime (0-86400)$duration
+.. index:: evpn mh neigh-holdtime (0-86400)$duration
 .. clicmd:: [no$no] evpn mh neigh-holdtime (0-86400)$duration
 
-.. index:: [no$no] evpn mh mac-holdtime (0-86400)$duration
+.. index:: evpn mh mac-holdtime (0-86400)$duration
 .. clicmd:: [no$no] evpn mh mac-holdtime (0-86400)$duration
 
 Startup delay
@@ -2728,7 +2832,7 @@ and EVPN network to converge before enabling the ESs. For this duration the
 ES bonds are held protodown. The startup delay is configurable via the
 following zebra command -
 
-.. index:: [no] evpn mh startup-delay(0-3600)$duration
+.. index:: evpn mh startup-delay(0-3600)$duration
 .. clicmd:: [no] evpn mh startup-delay(0-3600)$duration
 
 +Support with VRF network namespace backend
@@ -2787,7 +2891,7 @@ advertisement to take effect is 60 seconds. The conditional advertisement can ta
 effect depending on when the tracked route is removed from the BGP table and
 when the next instance of the BGP scanner occurs.
 
-.. index:: [no] neighbor A.B.C.D advertise-map NAME [exist-map|non-exist-map] NAME
+.. index:: neighbor A.B.C.D advertise-map NAME [exist-map|non-exist-map] NAME
 .. clicmd:: [no] neighbor A.B.C.D advertise-map NAME [exist-map|non-exist-map] NAME
 
    This command enables BGP scanner process to monitor routes specified by
@@ -2956,44 +3060,44 @@ Debugging
    Display Listen sockets and the vrf that created them.  Useful for debugging of when
    listen is not working and this is considered a developer debug statement.
 
-.. index:: [no] debug bgp neighbor-events
+.. index:: debug bgp neighbor-events
 .. clicmd:: [no] debug bgp neighbor-events
 
    Enable or disable debugging for neighbor events. This provides general
    information on BGP events such as peer connection / disconnection, session
    establishment / teardown, and capability negotiation.
 
-.. index:: [no] debug bgp updates
+.. index:: debug bgp updates
 .. clicmd:: [no] debug bgp updates
 
    Enable or disable debugging for BGP updates. This provides information on
    BGP UPDATE messages transmitted and received between local and remote
    instances.
 
-.. index:: [no] debug bgp keepalives
+.. index:: debug bgp keepalives
 .. clicmd:: [no] debug bgp keepalives
 
    Enable or disable debugging for BGP keepalives. This provides information on
    BGP KEEPALIVE messages transmitted and received between local and remote
    instances.
 
-.. index:: [no] debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>
+.. index:: debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>
 .. clicmd:: [no] debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>
 
    Enable or disable debugging for bestpath selection on the specified prefix.
 
-.. index:: [no] debug bgp nht
+.. index:: debug bgp nht
 .. clicmd:: [no] debug bgp nht
 
    Enable or disable debugging of BGP nexthop tracking.
 
-.. index:: [no] debug bgp update-groups
+.. index:: debug bgp update-groups
 .. clicmd:: [no] debug bgp update-groups
 
    Enable or disable debugging of dynamic update groups. This provides general
    information on group creation, deletion, join and prune events.
 
-.. index:: [no] debug bgp zebra
+.. index:: debug bgp zebra
 .. clicmd:: [no] debug bgp zebra
 
    Enable or disable debugging of communications between *bgpd* and *zebra*.
@@ -3007,7 +3111,7 @@ Dumping Messages and Routing Tables
 .. index:: dump bgp all-et PATH [INTERVAL]
 .. clicmd:: dump bgp all-et PATH [INTERVAL]
 
-.. index:: no dump bgp all [PATH] [INTERVAL]
+.. index:: dump bgp all [PATH] [INTERVAL]
 .. clicmd:: no dump bgp all [PATH] [INTERVAL]
 
    Dump all BGP packet and events to `path` file.
@@ -3022,7 +3126,7 @@ Dumping Messages and Routing Tables
 .. index:: dump bgp updates-et PATH [INTERVAL]
 .. clicmd:: dump bgp updates-et PATH [INTERVAL]
 
-.. index:: no dump bgp updates [PATH] [INTERVAL]
+.. index:: dump bgp updates [PATH] [INTERVAL]
 .. clicmd:: no dump bgp updates [PATH] [INTERVAL]
 
    Dump only BGP updates messages to `path` file.
@@ -3037,7 +3141,7 @@ Dumping Messages and Routing Tables
 .. index:: dump bgp routes-mrt PATH INTERVAL
 .. clicmd:: dump bgp routes-mrt PATH INTERVAL
 
-.. index:: no dump bgp route-mrt [PATH] [INTERVAL]
+.. index:: dump bgp route-mrt [PATH] [INTERVAL]
 .. clicmd:: no dump bgp route-mrt [PATH] [INTERVAL]
 
    Dump whole BGP routing table to `path`. This is heavy process. The path
@@ -3333,6 +3437,32 @@ attribute.
 
    If ``json`` option is specified, output is displayed in JSON format.
 
+.. index:: show bgp labelpool <chunks|inuse|ledger|requests|summary> [json] 
+.. clicmd:: show bgp labelpool <chunks|inuse|ledger|requests|summary> [json]
+
+   These commands display information about the BGP labelpool used for
+   the association of MPLS labels with routes for L3VPN and Labeled Unicast
+
+   If ``chunks`` option is specified, output shows the current list of label
+   chunks granted to BGP by Zebra, indicating the start and end label in
+   each chunk
+
+   If ``inuse`` option is specified, output shows the current inuse list of
+   label to prefix mappings
+
+   If ``ledger`` option is specified, output shows ledger list of all
+   label requests made per prefix
+
+   If ``requests`` option is specified, output shows current list of label
+   requests which have not yet been fulfilled by the labelpool
+
+   If ``summary`` option is specified, output is a summary of the counts for
+   the chunks, inuse, ledger and requests list along with the count of
+   outstanding chunk requests to Zebra and the nummber of zebra reconnects
+   that have happened
+
+   If ``json`` option is specified, output is displayed in JSON format.
+
 .. _bgp-display-routes-by-lcommunity:
 
 Displaying Routes by Large Community Attribute
@@ -3437,7 +3567,7 @@ with:
 .. index:: neighbor PEER route-reflector-client
 .. clicmd:: neighbor PEER route-reflector-client
 
-.. index:: no neighbor PEER route-reflector-client
+.. index:: neighbor PEER route-reflector-client
 .. clicmd:: no neighbor PEER route-reflector-client
 
 To avoid single points of failure, multiple route reflectors can be configured.
@@ -3448,7 +3578,7 @@ by route reflectors to avoid looping.
 .. index:: bgp cluster-id A.B.C.D
 .. clicmd:: bgp cluster-id A.B.C.D
 
-.. index:: [no] bgp no-rib
+.. index:: bgp no-rib
 .. clicmd:: [no] bgp no-rib
 
 To set and unset the BGP daemon ``-n`` / ``--no_kernel`` options during runtime
@@ -3462,6 +3592,15 @@ starting the daemon and the configuration gets saved, the option will persist
 unless removed from the configuration with the negating command prior to the
 configuration write operation.
 
+.. index:: bgp send-extra-data zebra
+.. clicmd:: [no] bgp send-extra-data zebra
+
+This Command turns off the ability of BGP to send extra data to zebra.
+In this case it's the AS-Path being used for the path.  The default behavior
+in BGP is to send this data and to turn it off enter the no form of the command.
+If extra data was sent to zebra, and this command is turned on there is no
+effort to clean up this data in the rib.
+
 .. _bgp-suppress-fib:
 
 Suppressing routes not installed in FIB
@@ -3503,9 +3642,14 @@ status in FIB:
 7. If the route which is already installed in dataplane is removed for some
    reason, sending withdraw message to peers is not currently supported.
 
-.. index:: [no] bgp suppress-fib-pending
+.. index:: bgp suppress-fib-pending
 .. clicmd:: [no] bgp suppress-fib-pending
 
+   This command is applicable at the global level and at an individual
+   bgp level.  If applied at the global level all bgp instances will
+   wait for fib installation before announcing routes and there is no
+   way to turn it off for a particular bgp vrf.
+
 .. _routing-policy:
 
 Routing Policy
index 915270a5626e87f91b2b820f3e57688674adf24c..4ce2e280c7be8f39cc9c66a2c99690d4808daab1 100644 (file)
@@ -73,7 +73,7 @@ EIGRP Configuration
    carrying out any of the EIGRP commands.  Specify vrf NAME if you want
    eigrp to work within the specified vrf.
 
-.. index:: no router eigrp (1-65535) [vrf NAME]
+.. index:: router eigrp (1-65535) [vrf NAME]
 .. clicmd:: no router eigrp (1-65535) [vrf NAME]
 
    Disable EIGRP.
@@ -81,7 +81,7 @@ EIGRP Configuration
 .. index:: network NETWORK
 .. clicmd:: network NETWORK
 
-.. index:: no network NETWORK
+.. index:: network NETWORK
 .. clicmd:: no network NETWORK
 
    Set the EIGRP enable interface by `network`. The interfaces which
@@ -107,7 +107,7 @@ EIGRP Configuration
 .. index:: passive-interface (IFNAME|default)
 .. clicmd:: passive-interface (IFNAME|default)
 
-.. index:: no passive-interface IFNAME
+.. index:: passive-interface IFNAME
 .. clicmd:: no passive-interface IFNAME
 
    This command sets the specified interface to passive mode. On passive mode
@@ -129,7 +129,7 @@ How to Announce EIGRP route
 .. index:: redistribute kernel metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)
 .. clicmd:: redistribute kernel metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)
 
-.. index:: no redistribute kernel
+.. index:: redistribute kernel
 .. clicmd:: no redistribute kernel
 
    `redistribute kernel` redistributes routing information from kernel route
@@ -141,7 +141,7 @@ How to Announce EIGRP route
 .. index:: redistribute static metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)
 .. clicmd:: redistribute static metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)
 
-.. index:: no redistribute static
+.. index:: redistribute static
 .. clicmd:: no redistribute static
 
    `redistribute static` redistributes routing information from static route
@@ -153,7 +153,7 @@ How to Announce EIGRP route
 .. index:: redistribute connected metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)
 .. clicmd:: redistribute connected metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)
 
-.. index:: no redistribute connected
+.. index:: redistribute connected
 .. clicmd:: no redistribute connected
 
    Redistribute connected routes into the EIGRP tables. `no redistribute
@@ -167,7 +167,7 @@ How to Announce EIGRP route
 .. index:: redistribute ospf metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)
 .. clicmd:: redistribute ospf metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)
 
-.. index:: no redistribute ospf
+.. index:: redistribute ospf
 .. clicmd:: no redistribute ospf
 
    `redistribute ospf` redistributes routing information from ospf route
@@ -179,7 +179,7 @@ How to Announce EIGRP route
 .. index:: redistribute bgp metric  (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)
 .. clicmd:: redistribute bgp metric  (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)
 
-.. index:: no redistribute bgp
+.. index:: redistribute bgp
 .. clicmd:: no redistribute bgp
 
    `redistribute bgp` redistributes routing information from bgp route entries
index cf0f937c13ccb4442ee759b63728e813baeb6ab0..a74d3e098b1239852cebfd6069e476714b469052 100644 (file)
@@ -35,7 +35,7 @@ in the configuration:
 .. index:: router openfabric WORD
 .. clicmd:: router openfabric WORD
 
-.. index:: no router openfabric WORD
+.. index:: router openfabric WORD
 .. clicmd:: no router openfabric WORD
 
    Enable or disable the OpenFabric process by specifying the OpenFabric domain with
@@ -44,7 +44,7 @@ in the configuration:
 .. index:: net XX.XXXX. ... .XXX.XX
 .. clicmd:: net XX.XXXX. ... .XXX.XX
 
-.. index:: no net XX.XXXX. ... .XXX.XX
+.. index:: net XX.XXXX. ... .XXX.XX
 .. clicmd:: no net XX.XXXX. ... .XXX.XX
 
    Set/Unset network entity title (NET) provided in ISO format.
@@ -52,7 +52,7 @@ in the configuration:
 .. index:: domain-password [clear | md5] <password>
 .. clicmd:: domain-password [clear | md5] <password>
 
-.. index:: no domain-password
+.. index:: domain-password
 .. clicmd:: no domain-password
 
    Configure the authentication password for a domain, as clear text or md5 one.
@@ -60,7 +60,7 @@ in the configuration:
 .. index:: log-adjacency-changes
 .. clicmd:: log-adjacency-changes
 
-.. index:: no log-adjacency-changes
+.. index:: log-adjacency-changes
 .. clicmd:: no log-adjacency-changes
 
    Log changes in adjacency state.
@@ -68,7 +68,7 @@ in the configuration:
 .. index:: set-overload-bit
 .. clicmd:: set-overload-bit
 
-.. index:: no set-overload-bit
+.. index:: set-overload-bit
 .. clicmd:: no set-overload-bit
 
    Set overload bit to avoid any transit traffic.
@@ -76,7 +76,7 @@ in the configuration:
 .. index:: purge-originator
 .. clicmd:: purge-originator
 
-.. index:: no purge-originator
+.. index:: purge-originator
 .. clicmd:: no purge-originator
 
    Enable or disable :rfc:`6232` purge originator identification.
@@ -84,7 +84,7 @@ in the configuration:
 .. index:: fabric-tier (0-14)
 .. clicmd:: fabric-tier (0-14)
 
-.. index:: no fabric-tier
+.. index:: fabric-tier
 .. clicmd:: no fabric-tier
 
    Configure a static tier number to advertise as location in the fabric
@@ -97,7 +97,7 @@ OpenFabric Timer
 .. index:: lsp-gen-interval (1-120)
 .. clicmd:: lsp-gen-interval (1-120)
 
-.. index:: no lsp-gen-interval
+.. index:: lsp-gen-interval
 .. clicmd:: no lsp-gen-interval
 
    Set minimum interval in seconds between regenerating same LSP.
@@ -105,7 +105,7 @@ OpenFabric Timer
 .. index:: lsp-refresh-interval (1-65235)
 .. clicmd:: lsp-refresh-interval (1-65235)
 
-.. index:: no lsp-refresh-interval
+.. index:: lsp-refresh-interval
 .. clicmd:: no lsp-refresh-interval
 
    Set LSP refresh interval in seconds.
@@ -113,7 +113,7 @@ OpenFabric Timer
 .. index:: max-lsp-lifetime (360-65535)
 .. clicmd:: max-lsp-lifetime (360-65535)
 
-.. index:: no max-lsp-lifetime
+.. index:: max-lsp-lifetime
 .. clicmd:: no max-lsp-lifetime
 
    Set LSP maximum LSP lifetime in seconds.
@@ -121,7 +121,7 @@ OpenFabric Timer
 .. index:: spf-interval (1-120)
 .. clicmd:: spf-interval (1-120)
 
-.. index:: no spf-interval
+.. index:: spf-interval
 .. clicmd:: no spf-interval
 
    Set minimum interval between consecutive SPF calculations in seconds.
@@ -134,7 +134,7 @@ OpenFabric interface
 .. index:: ip router openfabric WORD
 .. clicmd:: ip router openfabric WORD
 
-.. index:: no ip router openfabric WORD
+.. index:: ip router openfabric WORD
 .. clicmd:: no ip router openfabric WORD
 
 .. _ip-router-openfabric-word:
@@ -146,7 +146,7 @@ OpenFabric interface
 .. index:: openfabric csnp-interval (1-600)
 .. clicmd:: openfabric csnp-interval (1-600)
 
-.. index:: no openfabric csnp-interval
+.. index:: openfabric csnp-interval
 .. clicmd:: no openfabric csnp-interval
 
    Set CSNP interval in seconds.
@@ -154,7 +154,7 @@ OpenFabric interface
 .. index:: openfabric hello-interval (1-600)
 .. clicmd:: openfabric hello-interval (1-600)
 
-.. index:: no openfabric hello-interval
+.. index:: openfabric hello-interval
 .. clicmd:: no openfabric hello-interval
 
    Set Hello interval in seconds.
@@ -162,7 +162,7 @@ OpenFabric interface
 .. index:: openfabric hello-multiplier (2-100)
 .. clicmd:: openfabric hello-multiplier (2-100)
 
-.. index:: no openfabric hello-multiplier
+.. index:: openfabric hello-multiplier
 .. clicmd:: no openfabric hello-multiplier
 
    Set multiplier for Hello holding time.
@@ -170,7 +170,7 @@ OpenFabric interface
 .. index:: openfabric metric (0-16777215)
 .. clicmd:: openfabric metric (0-16777215)
 
-.. index:: no openfabric metric
+.. index:: openfabric metric
 .. clicmd:: no openfabric metric
 
    Set interface metric value.
@@ -178,7 +178,7 @@ OpenFabric interface
 .. index:: openfabric passive
 .. clicmd:: openfabric passive
 
-.. index:: no openfabric passive
+.. index:: openfabric passive
 .. clicmd:: no openfabric passive
 
    Configure the passive mode for this interface.
@@ -186,7 +186,7 @@ OpenFabric interface
 .. index:: openfabric password [clear | md5] <password>
 .. clicmd:: openfabric password [clear | md5] <password>
 
-.. index:: no openfabric password
+.. index:: openfabric password
 .. clicmd:: no openfabric password
 
    Configure the authentication password (clear or encoded text) for the
@@ -195,7 +195,7 @@ OpenFabric interface
 .. index:: openfabric psnp-interval (1-120)
 .. clicmd:: openfabric psnp-interval (1-120)
 
-.. index:: no openfabric psnp-interval
+.. index:: openfabric psnp-interval
 .. clicmd:: no openfabric psnp-interval
 
    Set PSNP interval in seconds.
@@ -267,7 +267,7 @@ Debugging OpenFabric
 .. index:: debug openfabric adj-packets
 .. clicmd:: debug openfabric adj-packets
 
-.. index:: no debug openfabric adj-packets
+.. index:: debug openfabric adj-packets
 .. clicmd:: no debug openfabric adj-packets
 
 OpenFabric Adjacency related packets.
@@ -275,7 +275,7 @@ OpenFabric Adjacency related packets.
 .. index:: debug openfabric checksum-errors
 .. clicmd:: debug openfabric checksum-errors
 
-.. index:: no debug openfabric checksum-errors
+.. index:: debug openfabric checksum-errors
 .. clicmd:: no debug openfabric checksum-errors
 
 OpenFabric LSP checksum errors.
@@ -283,7 +283,7 @@ OpenFabric LSP checksum errors.
 .. index:: debug openfabric events
 .. clicmd:: debug openfabric events
 
-.. index:: no debug openfabric events
+.. index:: debug openfabric events
 .. clicmd:: no debug openfabric events
 
 OpenFabric Events.
@@ -291,7 +291,7 @@ OpenFabric Events.
 .. index:: debug openfabric local-updates
 .. clicmd:: debug openfabric local-updates
 
-.. index:: no debug openfabric local-updates
+.. index:: debug openfabric local-updates
 .. clicmd:: no debug openfabric local-updates
 
 OpenFabric local update packets.
@@ -299,7 +299,7 @@ OpenFabric local update packets.
 .. index:: debug openfabric lsp-gen
 .. clicmd:: debug openfabric lsp-gen
 
-.. index:: no debug openfabric lsp-gen
+.. index:: debug openfabric lsp-gen
 .. clicmd:: no debug openfabric lsp-gen
 
 Generation of own LSPs.
@@ -307,7 +307,7 @@ Generation of own LSPs.
 .. index:: debug openfabric lsp-sched
 .. clicmd:: debug openfabric lsp-sched
 
-.. index:: no debug openfabric lsp-sched
+.. index:: debug openfabric lsp-sched
 .. clicmd:: no debug openfabric lsp-sched
 
 Debug scheduling of generation of own LSPs.
@@ -315,7 +315,7 @@ Debug scheduling of generation of own LSPs.
 .. index:: debug openfabric packet-dump
 .. clicmd:: debug openfabric packet-dump
 
-.. index:: no debug openfabric packet-dump
+.. index:: debug openfabric packet-dump
 .. clicmd:: no debug openfabric packet-dump
 
 OpenFabric packet dump.
@@ -323,7 +323,7 @@ OpenFabric packet dump.
 .. index:: debug openfabric protocol-errors
 .. clicmd:: debug openfabric protocol-errors
 
-.. index:: no debug openfabric protocol-errors
+.. index:: debug openfabric protocol-errors
 .. clicmd:: no debug openfabric protocol-errors
 
 OpenFabric LSP protocol errors.
@@ -331,7 +331,7 @@ OpenFabric LSP protocol errors.
 .. index:: debug openfabric route-events
 .. clicmd:: debug openfabric route-events
 
-.. index:: no debug openfabric route-events
+.. index:: debug openfabric route-events
 .. clicmd:: no debug openfabric route-events
 
 OpenFabric Route related events.
@@ -339,7 +339,7 @@ OpenFabric Route related events.
 .. index:: debug openfabric snp-packets
 .. clicmd:: debug openfabric snp-packets
 
-.. index:: no debug openfabric snp-packets
+.. index:: debug openfabric snp-packets
 .. clicmd:: no debug openfabric snp-packets
 
 OpenFabric CSNP/PSNP packets.
@@ -353,13 +353,13 @@ OpenFabric CSNP/PSNP packets.
 .. index:: debug openfabric spf-triggers
 .. clicmd:: debug openfabric spf-triggers
 
-.. index:: no debug openfabric spf-events
+.. index:: debug openfabric spf-events
 .. clicmd:: no debug openfabric spf-events
 
-.. index:: no debug openfabric spf-statistics
+.. index:: debug openfabric spf-statistics
 .. clicmd:: no debug openfabric spf-statistics
 
-.. index:: no debug openfabric spf-triggers
+.. index:: debug openfabric spf-triggers
 .. clicmd:: no debug openfabric spf-triggers
 
 OpenFabric Shortest Path First Events, Timing and Statistic Data and triggering
@@ -368,7 +368,7 @@ events.
 .. index:: debug openfabric update-packets
 .. clicmd:: debug openfabric update-packets
 
-.. index:: no debug openfabric update-packets
+.. index:: debug openfabric update-packets
 .. clicmd:: no debug openfabric update-packets
 
 Update related packets.
index 98b768412db8e8ab049c14c9579a70a877667195..910da7246da95f2455cf6027a32ea46d9a6753b7 100644 (file)
@@ -98,7 +98,7 @@ is defined, and no match is found, default deny is applied.
    In the case of no le or ge command, the prefix length must match exactly the
    length specified in the prefix list.
 
-.. index:: no ip prefix-list NAME
+.. index:: ip prefix-list NAME
 .. clicmd:: no ip prefix-list NAME
 
 .. _ip-prefix-list-description:
@@ -112,7 +112,7 @@ ip prefix-list description
    Descriptions may be added to prefix lists. This command adds a
    description to the prefix list.
 
-.. index:: no ip prefix-list NAME description [DESC]
+.. index:: ip prefix-list NAME description [DESC]
 .. clicmd:: no ip prefix-list NAME description [DESC]
 
    Deletes the description from a prefix list. It is possible to use the
@@ -129,7 +129,7 @@ ip prefix-list sequential number control
    With this command, the IP prefix list sequential number is displayed.
    This is the default behavior.
 
-.. index:: no ip prefix-list sequence-number
+.. index:: ip prefix-list sequence-number
 .. clicmd:: no ip prefix-list sequence-number
 
    With this command, the IP prefix list sequential number is not
index d3eb25a7c7fc6a31bdc37b384fc2c4b0b6ed0cd1..c303ebdba4018182255d63c0086d9a5d40296180 100644 (file)
@@ -141,7 +141,7 @@ twice the traffic, or slow down the traffic (filtering costs). To limit
 Flowspec to one specific interface, use the following command, under
 `flowspec address-family` node.
 
-.. index:: [no] local-install <IFNAME | any>
+.. index:: local-install <IFNAME | any>
 .. clicmd:: [no] local-install <IFNAME | any>
 
 By default, Flowspec is activated on all interfaces. Installing it to a named
@@ -168,7 +168,7 @@ following:
 - The first VRF with the matching Route Target will be selected to route traffic
   to. Use the following command under ipv4 unicast address-family node
 
-.. index:: [no] rt redirect import RTLIST...
+.. index:: rt redirect import RTLIST...
 .. clicmd:: [no] rt redirect import RTLIST...
 
 In order to illustrate, if the Route Target configured in the Flowspec entry is
@@ -241,14 +241,14 @@ match.
    ``TABLEID`` is the table number identifier referencing the non standard
    routing table used in this example.
 
-.. index:: [no] debug bgp flowspec
+.. index:: debug bgp flowspec
 .. clicmd:: [no] debug bgp flowspec
 
    You can troubleshoot Flowspec, or BGP policy based routing. For instance, if
    you encounter some issues when decoding a Flowspec entry, you should enable
    :clicmd:`debug bgp flowspec`.
 
-.. index:: [no] debug bgp pbr [error]
+.. index:: debug bgp pbr [error]
 .. clicmd:: [no] debug bgp pbr [error]
 
    If you fail to apply the flowspec entry into *zebra*, there should be some
index 8ac997f8dd3e2fe1e18e51787379856006f9fe2c..7b9464668b252cbf9622b77a93c960d2850f8e35 100644 (file)
@@ -29,6 +29,7 @@ Basics
    ipv6
    kernel
    snmp
+   scripting
 .. modules
 
 #########
@@ -50,6 +51,7 @@ Protocols
    nhrpd
    ospfd
    ospf6d
+   pathd
    pim
    pbr
    ripd
index 382d71b71f5744588191e1be610d81599ff6dfbf..a13e6ce43ba923fee22c9caa7db61a04c02be9cc 100644 (file)
@@ -362,6 +362,10 @@ options from the list below.
 
    Set hardcoded rpaths in the executable [default=yes].
 
+.. option:: --enable-scripting
+
+   Enable Lua scripting [default=no].
+
 You may specify any combination of the above options to the configure
 script. By default, the executables are placed in :file:`/usr/local/sbin`
 and the configuration files in :file:`/usr/local/etc`. The :file:`/usr/local/`
@@ -382,6 +386,10 @@ options to the configuration script.
    Configure zebra to use `dir` for local state files, such as pid files and
    unix sockets.
 
+.. option:: --with-scriptdir <dir>
+
+   Look for Lua scripts in ``dir`` [``prefix``/etc/frr/scripts].
+
 .. option:: --with-yangmodelsdir <dir>
 
    Look for YANG modules in `dir` [`prefix`/share/yang]. Note that the FRR
index d1477ddcdb858267dfc337aada75f908e0cea83f..26341f04f13b229c1e745611149c47ed6ad3909a 100644 (file)
@@ -17,7 +17,7 @@ no longer possible.
 Router Advertisement
 ====================
 
-.. index:: no ipv6 nd suppress-ra
+.. index:: ipv6 nd suppress-ra
 .. clicmd:: no ipv6 nd suppress-ra
 
    Send router advertisement messages.
@@ -57,9 +57,7 @@ Router Advertisement
 
      Default: not set, i.e. hosts do not assume a complete IP address is placed.
 
-.. index::
-   single: no ipv6 nd ra-interval [(1-1800)]
-   single: no ipv6 nd ra-interval [(1-1800)]
+.. index:: ipv6 nd ra-interval [(1-1800)]
 .. clicmd:: [no] ipv6 nd ra-interval [(1-1800)]
 
    The maximum time allowed between sending unsolicited multicast router
@@ -67,18 +65,13 @@ Router Advertisement
    Default: ``600``
 
 .. index:: ipv6 nd ra-interval msec (70-1800000)
-.. index::
-   single: no ipv6 nd ra-interval [msec (70-1800000)]
-   single: ipv6 nd ra-interval msec (70-1800000)
 .. clicmd:: [no] ipv6 nd ra-interval [msec (70-1800000)]
 
    The maximum time allowed between sending unsolicited multicast router
    advertisements from the interface, in milliseconds.
    Default: ``600000``
 
-.. index::
-   single: ipv6 nd ra-fast-retrans
-   single: no ipv6 nd ra-fast-retrans
+.. index:: ipv6 nd ra-fast-retrans
 .. clicmd:: [no] ipv6 nd ra-fast-retrans
 
    RFC4861 states that consecutive RA packets should be sent no more
@@ -90,9 +83,7 @@ Router Advertisement
    and neighbor establishment.
    Default: enabled
 
-.. index::
-   single: ipv6 nd ra-retrans-interval (0-4294967295)
-   single: no ipv6 nd retrans-interval [(0-4294967295)]
+.. index:: ipv6 nd ra-retrans-interval (0-4294967295)
 .. clicmd:: [no] ipv6 nd ra-retrans-interval [(0-4294967295)]
 
    The value to be placed in the retrans timer field of router advertisements
@@ -102,9 +93,7 @@ Router Advertisement
    msec.
    Default: ``0``
 
-.. index::
-   single: ipv6 nd ra-hop-limit (0-255)
-   single: no ipv6 nd ra-hop-limit [(0-255)]
+.. index:: ipv6 nd ra-hop-limit (0-255)
 .. clicmd:: [no] ipv6 nd ra-hop-limit [(0-255)]
 
    The value to be placed in the hop count field of router advertisements sent
@@ -113,9 +102,7 @@ Router Advertisement
    router.  Must be between zero or 255 hops.
    Default: ``64``
 
-.. index::
-   single: ipv6 nd ra-lifetime (0-9000)
-   single: no ipv6 nd ra-lifetime [(0-9000)]
+.. index:: ipv6 nd ra-lifetime (0-9000)
 .. clicmd:: [no] ipv6 nd ra-lifetime [(0-9000)]
 
    The value to be placed in the Router Lifetime field of router advertisements
@@ -126,9 +113,7 @@ Router Advertisement
    (or default) and 9000 seconds.
    Default: ``1800``
 
-.. index::
-   single: no ipv6 nd reachable-time [(1-3600000)]
-   single: ipv6 nd reachable-time (1-3600000)
+.. index:: ipv6 nd reachable-time (1-3600000)
 .. clicmd:: [no] ipv6 nd reachable-time [(1-3600000)]
 
    The value to be placed in the Reachable Time field in the Router
@@ -137,9 +122,7 @@ Router Advertisement
    means unspecified (by this router).
    Default: ``0``
 
-.. index::
-   single: ipv6 nd managed-config-flag
-   single: no ipv6 nd managed-config-flag
+.. index:: ipv6 nd managed-config-flag
 .. clicmd:: [no] ipv6 nd managed-config-flag
 
    Set/unset flag in IPv6 router advertisements which indicates to hosts that
@@ -148,9 +131,7 @@ Router Advertisement
    autoconfiguration.
    Default: not set
 
-.. index::
-   single: ipv6 nd other-config-flag
-   single: no ipv6 nd other-config-flag
+.. index:: ipv6 nd other-config-flag
 .. clicmd:: [no] ipv6 nd other-config-flag
 
    Set/unset flag in IPv6 router advertisements which indicates to hosts that
@@ -158,9 +139,7 @@ Router Advertisement
    information other than addresses.
    Default: not set
 
-.. index::
-   single: ipv6 nd home-agent-config-flag
-   single: no ipv6 nd home-agent-config-flag
+.. index:: ipv6 nd home-agent-config-flag
 .. clicmd:: [no] ipv6 nd home-agent-config-flag
 
    Set/unset flag in IPv6 router advertisements which indicates to hosts that
@@ -169,9 +148,7 @@ Router Advertisement
 
 .. index:: ipv6 nd home-agent-preference (0-65535)
 
-.. index::
-   single: no ipv6 nd home-agent-preference [(0-65535)]
-   single: ipv6 nd home-agent-preference (0-65535)
+.. index:: ipv6 nd home-agent-preference (0-65535)
 .. clicmd:: [no] ipv6 nd home-agent-preference [(0-65535)]
 
    The value to be placed in Home Agent Option, when Home Agent config flag is
@@ -179,9 +156,7 @@ Router Advertisement
    stands for the lowest preference possible.
    Default: ``0``
 
-.. index::
-   single: ipv6 nd home-agent-lifetime (0-65520)
-   single: no ipv6 nd home-agent-lifetime (0-65520)
+.. index:: ipv6 nd home-agent-lifetime (0-65520)
 .. clicmd:: [no] ipv6 nd home-agent-lifetime [(0-65520)]
 
    The value to be placed in Home Agent Option, when Home Agent config flag is set,
@@ -190,26 +165,20 @@ Router Advertisement
 
    Default: ``0``
 
-.. index::
-   single: ipv6 nd adv-interval-option
-   single: no ipv6 nd adv-interval-option
+.. index:: ipv6 nd adv-interval-option
 .. clicmd:: [no] ipv6 nd adv-interval-option
 
    Include an Advertisement Interval option which indicates to hosts the maximum time,
    in milliseconds, between successive unsolicited Router Advertisements.
    Default: not set
 
-.. index::
-   single: ipv6 nd router-preference (high|medium|low)
-   single: no ipv6 nd router-preference (high|medium|low)
+.. index:: ipv6 nd router-preference (high|medium|low)
 .. clicmd:: [no] ipv6 nd router-preference [(high|medium|low)]
 
    Set default router preference in IPv6 router advertisements per RFC4191.
    Default: medium
 
-.. index::
-   single: ipv6 nd mtu (1-65535)
-   single: no ipv6 nd mtu [(1-65535)]
+.. index:: ipv6 nd mtu (1-65535)
 .. clicmd:: [no] ipv6 nd mtu [(1-65535)]
 
    Include an MTU (type 5) option in each RA packet to assist the attached
@@ -218,9 +187,7 @@ Router Advertisement
 
    Default: don't advertise any MTU option.
 
-.. index::
-   single: ipv6 nd rdnss ipv6address [lifetime]
-   single: no ipv6 nd rdnss ipv6address [lifetime]
+.. index:: ipv6 nd rdnss ipv6address [lifetime]
 .. clicmd:: [no] ipv6 nd rdnss ipv6address [lifetime]
 
    Recursive DNS server address to advertise using the RDNSS (type 25) option
@@ -238,9 +205,7 @@ Router Advertisement
 
    Default: do not emit RDNSS option
 
-.. index::
-   single: ipv6 nd dnssl domain-name-suffix [lifetime]
-   single: no ipv6 nd dnssl domain-name-suffix [lifetime]
+.. index:: ipv6 nd dnssl domain-name-suffix [lifetime]
 .. clicmd:: [no] ipv6 nd dnssl domain-name-suffix [lifetime]
 
    Advertise DNS search list using the DNSSL (type 31) option described in
index 98f5aff7dbdb759c6c527a92252243cb782bbbb5..7e198564b5022342892a5a93c0e931fc8ad52706 100644 (file)
@@ -33,7 +33,7 @@ ISIS router
 To start the ISIS process you have to specify the ISIS router. As of this
 writing, *isisd* does not support multiple ISIS processes.
 
-.. index:: [no] router isis WORD [vrf NAME]
+.. index:: router isis WORD [vrf NAME]
 .. clicmd:: [no] router isis WORD [vrf NAME]
 
    Enable or disable the ISIS process by specifying the ISIS domain with
@@ -44,7 +44,7 @@ writing, *isisd* does not support multiple ISIS processes.
 .. index:: net XX.XXXX. ... .XXX.XX
 .. clicmd:: net XX.XXXX. ... .XXX.XX
 
-.. index:: no net XX.XXXX. ... .XXX.XX
+.. index:: net XX.XXXX. ... .XXX.XX
 .. clicmd:: no net XX.XXXX. ... .XXX.XX
 
    Set/Unset network entity title (NET) provided in ISO format.
@@ -52,7 +52,7 @@ writing, *isisd* does not support multiple ISIS processes.
 .. index:: hostname dynamic
 .. clicmd:: hostname dynamic
 
-.. index:: no hostname dynamic
+.. index:: hostname dynamic
 .. clicmd:: no hostname dynamic
 
    Enable support for dynamic hostname.
@@ -63,10 +63,10 @@ writing, *isisd* does not support multiple ISIS processes.
 .. index:: domain-password [clear | md5] <password>
 .. clicmd:: domain-password [clear | md5] <password>
 
-.. index:: no area-password
+.. index:: area-password
 .. clicmd:: no area-password
 
-.. index:: no domain-password
+.. index:: domain-password
 .. clicmd:: no domain-password
 
    Configure the authentication password for an area, respectively a domain, as
@@ -75,7 +75,7 @@ writing, *isisd* does not support multiple ISIS processes.
 .. index:: log-adjacency-changes
 .. clicmd:: log-adjacency-changes
 
-.. index:: no log-adjacency-changes
+.. index:: log-adjacency-changes
 .. clicmd:: no log-adjacency-changes
 
    Log changes in adjacency state.
@@ -83,7 +83,7 @@ writing, *isisd* does not support multiple ISIS processes.
 .. index:: metric-style [narrow | transition | wide]
 .. clicmd:: metric-style [narrow | transition | wide]
 
-.. index:: no metric-style
+.. index:: metric-style
 .. clicmd:: no metric-style
 
    Set old-style (ISO 10589) or new-style packet formats:
@@ -98,7 +98,7 @@ writing, *isisd* does not support multiple ISIS processes.
 .. index:: set-overload-bit
 .. clicmd:: set-overload-bit
 
-.. index:: no set-overload-bit
+.. index:: set-overload-bit
 .. clicmd:: no set-overload-bit
 
    Set overload bit to avoid any transit traffic.
@@ -106,12 +106,12 @@ writing, *isisd* does not support multiple ISIS processes.
 .. index:: purge-originator
 .. clicmd:: purge-originator
 
-.. index:: no purge-originator
+.. index:: purge-originator
 .. clicmd:: no purge-originator
 
    Enable or disable :rfc:`6232` purge originator identification.
 
-.. index:: [no] lsp-mtu (128-4352)
+.. index:: lsp-mtu (128-4352)
 .. clicmd:: [no] lsp-mtu (128-4352)
 
    Configure the maximum size of generated LSPs, in bytes.
@@ -128,10 +128,10 @@ ISIS Timer
 .. index:: lsp-gen-interval [level-1 | level-2] (1-120)
 .. clicmd:: lsp-gen-interval [level-1 | level-2] (1-120)
 
-.. index:: no lsp-gen-interval
+.. index:: lsp-gen-interval
 .. clicmd:: no lsp-gen-interval
 
-.. index:: no lsp-gen-interval [level-1 | level-2]
+.. index:: lsp-gen-interval [level-1 | level-2]
 .. clicmd:: no lsp-gen-interval [level-1 | level-2]
 
    Set minimum interval in seconds between regenerating same LSP,
@@ -140,7 +140,7 @@ ISIS Timer
 .. index:: lsp-refresh-interval [level-1 | level-2] (1-65235)
 .. clicmd:: lsp-refresh-interval [level-1 | level-2] (1-65235)
 
-.. index:: no lsp-refresh-interval [level-1 | level-2]
+.. index:: lsp-refresh-interval [level-1 | level-2]
 .. clicmd:: no lsp-refresh-interval [level-1 | level-2]
 
    Set LSP refresh interval in seconds, globally, for an area (level-1) or a
@@ -152,10 +152,10 @@ ISIS Timer
 .. index:: max-lsp-lifetime [level-1 | level-2] (360-65535)
 .. clicmd:: max-lsp-lifetime [level-1 | level-2] (360-65535)
 
-.. index:: no max-lsp-lifetime
+.. index:: max-lsp-lifetime
 .. clicmd:: no max-lsp-lifetime
 
-.. index:: no max-lsp-lifetime [level-1 | level-2]
+.. index:: max-lsp-lifetime [level-1 | level-2]
 .. clicmd:: no max-lsp-lifetime [level-1 | level-2]
 
    Set LSP maximum LSP lifetime in seconds, globally, for an area (level-1) or
@@ -167,14 +167,49 @@ ISIS Timer
 .. index:: spf-interval [level-1 | level-2] (1-120)
 .. clicmd:: spf-interval [level-1 | level-2] (1-120)
 
-.. index:: no spf-interval
+.. index:: spf-interval
 .. clicmd:: no spf-interval
 
-.. index:: no spf-interval [level-1 | level-2]
+.. index:: spf-interval [level-1 | level-2]
 .. clicmd:: no spf-interval [level-1 | level-2]
 
    Set minimum interval between consecutive SPF calculations in seconds.
 
+.. _isis-fast-reroute:
+
+ISIS Fast-Reroute
+=================
+
+.. index:: spf prefix-priority [critical | high | medium] WORD
+.. clicmd:: spf prefix-priority [critical | high | medium] WORD
+
+.. index:: spf prefix-priority [critical | high | medium] WORD
+.. clicmd:: no spf prefix-priority [critical | high | medium] [WORD]
+
+   Assign a priority to the prefixes that match the specified access-list.
+
+.. index:: fast-reroute priority-limit [critical | high | medium] [level-1 | level-2]
+.. clicmd:: [no] fast-reroute priority-limit [critical | high | medium] [level-1 | level-2]
+
+   Limit LFA backup computation up to the specified prefix priority.
+
+.. index:: fast-reroute lfa tiebreaker [downstream | lowest-backup-metric | node-protecting] index (1-255) [level-1 | level-2]
+.. clicmd:: [no] fast-reroute lfa tiebreaker [downstream | lowest-backup-metric | node-protecting] index (1-255) [level-1 | level-2]
+
+   Configure a tie-breaker for multiple LFA backups. Lower indexes are processed
+   first.
+
+.. index:: fast-reroute load-sharing disable [level-1 | level-2]
+.. clicmd:: [no] fast-reroute load-sharing disable [level-1 | level-2]
+
+   Disable load sharing across multiple LFA backups.
+
+.. index:: fast-reroute remote-lfa prefix-list WORD [level-1 | level-2]
+.. clicmd:: [no] fast-reroute remote-lfa prefix-list [WORD] [level-1 | level-2]
+
+   Configure a prefix-list to select eligible PQ nodes (valid for all protected
+   interfaces).
+
 .. _isis-region:
 
 ISIS region
@@ -183,7 +218,7 @@ ISIS region
 .. index:: is-type [level-1 | level-1-2 | level-2-only]
 .. clicmd:: is-type [level-1 | level-1-2 | level-2-only]
 
-.. index:: no is-type
+.. index:: is-type
 .. clicmd:: no is-type
 
    Define the ISIS router behavior:
@@ -202,7 +237,8 @@ ISIS interface
 
 .. _ip-router-isis-word:
 
-.. index:: [no] <ip|ipv6> router isis WORD [vrf NAME]
+.. index:: ip router isis WORD [vrf NAME]
+.. index:: ipv6 router isis WORD [vrf NAME]
 .. clicmd:: [no] <ip|ipv6> router isis WORD [vrf NAME]
 
    Activate ISIS adjacency on this interface. Note that the name of ISIS
@@ -213,7 +249,7 @@ ISIS interface
 .. index:: isis circuit-type [level-1 | level-1-2 | level-2]
 .. clicmd:: isis circuit-type [level-1 | level-1-2 | level-2]
 
-.. index:: no isis circuit-type
+.. index:: isis circuit-type
 .. clicmd:: no isis circuit-type
 
    Configure circuit type for interface:
@@ -231,10 +267,10 @@ ISIS interface
 .. index:: isis csnp-interval (1-600) [level-1 | level-2]
 .. clicmd:: isis csnp-interval (1-600) [level-1 | level-2]
 
-.. index:: no isis csnp-interval
+.. index:: isis csnp-interval
 .. clicmd:: no isis csnp-interval
 
-.. index:: no isis csnp-interval [level-1 | level-2]
+.. index:: isis csnp-interval [level-1 | level-2]
 .. clicmd:: no isis csnp-interval [level-1 | level-2]
 
    Set CSNP interval in seconds globally, for an area (level-1) or a domain
@@ -251,10 +287,10 @@ ISIS interface
 .. index:: isis hello-interval (1-600) [level-1 | level-2]
 .. clicmd:: isis hello-interval (1-600) [level-1 | level-2]
 
-.. index:: no isis hello-interval
+.. index:: isis hello-interval
 .. clicmd:: no isis hello-interval
 
-.. index:: no isis hello-interval [level-1 | level-2]
+.. index:: isis hello-interval [level-1 | level-2]
 .. clicmd:: no isis hello-interval [level-1 | level-2]
 
    Set Hello interval in seconds globally, for an area (level-1) or a domain
@@ -266,10 +302,10 @@ ISIS interface
 .. index:: isis hello-multiplier (2-100) [level-1 | level-2]
 .. clicmd:: isis hello-multiplier (2-100) [level-1 | level-2]
 
-.. index:: no isis hello-multiplier
+.. index:: isis hello-multiplier
 .. clicmd:: no isis hello-multiplier
 
-.. index:: no isis hello-multiplier [level-1 | level-2]
+.. index:: isis hello-multiplier [level-1 | level-2]
 .. clicmd:: no isis hello-multiplier [level-1 | level-2]
 
    Set multiplier for Hello holding time globally, for an area (level-1) or a
@@ -281,10 +317,10 @@ ISIS interface
 .. index:: isis metric [(0-255) | (0-16777215)] [level-1 | level-2]
 .. clicmd:: isis metric [(0-255) | (0-16777215)] [level-1 | level-2]
 
-.. index:: no isis metric
+.. index:: isis metric
 .. clicmd:: no isis metric
 
-.. index:: no isis metric [level-1 | level-2]
+.. index:: isis metric [level-1 | level-2]
 .. clicmd:: no isis metric [level-1 | level-2]
 
    Set default metric value globally, for an area (level-1) or a domain
@@ -294,7 +330,7 @@ ISIS interface
 .. index:: isis network point-to-point
 .. clicmd:: isis network point-to-point
 
-.. index:: no isis network point-to-point
+.. index:: isis network point-to-point
 .. clicmd:: no isis network point-to-point
 
    Set network type to 'Point-to-Point' (broadcast by default).
@@ -302,7 +338,7 @@ ISIS interface
 .. index:: isis passive
 .. clicmd:: isis passive
 
-.. index:: no isis passive
+.. index:: isis passive
 .. clicmd:: no isis passive
 
    Configure the passive mode for this interface.
@@ -310,7 +346,7 @@ ISIS interface
 .. index:: isis password [clear | md5] <password>
 .. clicmd:: isis password [clear | md5] <password>
 
-.. index:: no isis password
+.. index:: isis password
 .. clicmd:: no isis password
 
    Configure the authentication password (clear or encoded text) for the
@@ -322,10 +358,10 @@ ISIS interface
 .. index:: isis priority (0-127) [level-1 | level-2]
 .. clicmd:: isis priority (0-127) [level-1 | level-2]
 
-.. index:: no isis priority
+.. index:: isis priority
 .. clicmd:: no isis priority
 
-.. index:: no isis priority [level-1 | level-2]
+.. index:: isis priority [level-1 | level-2]
 .. clicmd:: no isis priority [level-1 | level-2]
 
    Set priority for Designated Router election, globally, for the area
@@ -337,10 +373,10 @@ ISIS interface
 .. index:: isis psnp-interval (1-120) [level-1 | level-2]
 .. clicmd:: isis psnp-interval (1-120) [level-1 | level-2]
 
-.. index:: no isis psnp-interval
+.. index:: isis psnp-interval
 .. clicmd:: no isis psnp-interval
 
-.. index:: no isis psnp-interval [level-1 | level-2]
+.. index:: isis psnp-interval [level-1 | level-2]
 .. clicmd:: no isis psnp-interval [level-1 | level-2]
 
    Set PSNP interval in seconds globally, for an area (level-1) or a domain
@@ -349,17 +385,39 @@ ISIS interface
 .. index:: isis three-way-handshake
 .. clicmd:: isis three-way-handshake
 
-.. index:: no isis three-way-handshake
+.. index:: isis three-way-handshake
 .. clicmd:: no isis three-way-handshake
 
    Enable or disable :rfc:`5303` Three-Way Handshake for P2P adjacencies.
    Three-Way Handshake is enabled by default.
 
-.. index:: [no] isis fast-reroute ti-lfa [level-1|level-2] [node-protection]
+.. index:: isis fast-reroute lfa [level-1 | level-2]
+.. clicmd:: [no] isis fast-reroute lfa [level-1 | level-2]
+
+   Enable per-prefix LFA fast reroute link protection.
+
+.. index:: isis fast-reroute lfa [level-1 | level-2] exclude interface IFNAME
+.. clicmd:: [no] isis fast-reroute lfa [level-1 | level-2] exclude interface IFNAME
+
+   Exclude an interface from the LFA backup nexthop computation.
+
+.. index:: isis fast-reroute ti-lfa [level-1|level-2] [node-protection]
 .. clicmd:: [no] isis fast-reroute ti-lfa [level-1|level-2] [node-protection]
 
    Enable per-prefix TI-LFA fast reroute link or node protection.
 
+.. index:: isis fast-reroute remote-lfa tunnel mpls-ldp [level-1 | level-2]
+.. clicmd:: [no] isis fast-reroute remote-lfa tunnel mpls-ldp [level-1 | level-2]
+
+   Enable per-prefix Remote LFA fast reroute link protection. Note that other
+   routers in the network need to be configured to accept LDP targeted hello
+   messages in order for RLFA to work.
+
+.. index:: isis fast-reroute remote-lfa maximum-metric (1-16777215) [level-1 | level-2]
+.. clicmd:: [no] isis fast-reroute remote-lfa maximum-metric (1-16777215) [level-1 | level-2]
+
+   Limit Remote LFA PQ node selection within the specified metric.
+
 .. _showing-isis-information:
 
 Showing ISIS information
@@ -429,6 +487,12 @@ Showing ISIS information
    Show the ISIS routing table, as determined by the most recent SPF
    calculation.
 
+.. index:: show isis fast-reroute summary [level-1|level-2]
+.. clicmd:: show isis fast-reroute summary [level-1|level-2]
+
+   Show information about the number of prefixes having LFA protection,
+   and network-wide LFA coverage.
+
 .. _isis-traffic-engineering:
 
 Traffic Engineering
@@ -443,7 +507,7 @@ Traffic Engineering
 .. index:: mpls-te on
 .. clicmd:: mpls-te on
 
-.. index:: no mpls-te
+.. index:: mpls-te
 .. clicmd:: no mpls-te
 
    Enable Traffic Engineering LSP flooding.
@@ -451,7 +515,7 @@ Traffic Engineering
 .. index:: mpls-te router-address <A.B.C.D>
 .. clicmd:: mpls-te router-address <A.B.C.D>
 
-.. index:: no mpls-te router-address
+.. index:: mpls-te router-address
 .. clicmd:: no mpls-te router-address
 
    Configure stable IP address for MPLS-TE.
@@ -489,33 +553,33 @@ Known limitations:
  - No support for SRLB
  - Only one SRGB and default SPF Algorithm is supported
 
-.. index:: [no] segment-routing on
+.. index:: segment-routing on
 .. clicmd:: [no] segment-routing on
 
    Enable Segment Routing.
 
-.. index:: [no] segment-routing global-block (0-1048575) (0-1048575)
+.. index:: segment-routing global-block (0-1048575) (0-1048575)
 .. clicmd:: [no] segment-routing global-block (0-1048575) (0-1048575)
 
    Set the Segment Routing Global Block i.e. the label range used by MPLS
    to store label in the MPLS FIB for Prefix SID. Note that the block size
    may not exceed 65535.
 
-.. index:: [no] segment-routing local-block (0-1048575) (0-1048575)
+.. index:: segment-routing local-block (0-1048575) (0-1048575)
 .. clicmd:: [no] segment-routing local-block (0-1048575) (0-1048575)
 
    Set the Segment Routing Local Block i.e. the label range used by MPLS
    to store label in the MPLS FIB for Adjacency SID. Note that the block size
    may not exceed 65535.
 
-.. index:: [no] segment-routing node-msd (1-16)
+.. index:: segment-routing node-msd (1-16)
 .. clicmd:: [no] segment-routing node-msd (1-16)
 
    Set the Maximum Stack Depth supported by the router. The value depend of the
    MPLS dataplane. E.g. for Linux kernel, since version 4.13 the maximum value
    is 32.
 
-.. index:: [no] segment-routing prefix <A.B.C.D/M|X:X::X:X/M> <absolute (16-1048575)|index (0-65535)> [no-php-flag|explicit-null] [n-flag-clear]
+.. index:: segment-routing prefix <A.B.C.D/M|X:X::X:X/M> <absolute (16-1048575)|index (0-65535)> [no-php-flag|explicit-null] [n-flag-clear]
 .. clicmd:: [no] segment-routing prefix <A.B.C.D/M|X:X::X:X/M> <absolute (16-1048575)|index (0-65535) [no-php-flag|explicit-null] [n-flag-clear]
 
    Set the Segment Routing index or absolute label value for the specified
@@ -542,7 +606,7 @@ Debugging ISIS
 .. index:: debug isis adj-packets
 .. clicmd:: debug isis adj-packets
 
-.. index:: no debug isis adj-packets
+.. index:: debug isis adj-packets
 .. clicmd:: no debug isis adj-packets
 
    IS-IS Adjacency related packets.
@@ -550,7 +614,7 @@ Debugging ISIS
 .. index:: debug isis checksum-errors
 .. clicmd:: debug isis checksum-errors
 
-.. index:: no debug isis checksum-errors
+.. index:: debug isis checksum-errors
 .. clicmd:: no debug isis checksum-errors
 
    IS-IS LSP checksum errors.
@@ -558,7 +622,7 @@ Debugging ISIS
 .. index:: debug isis events
 .. clicmd:: debug isis events
 
-.. index:: no debug isis events
+.. index:: debug isis events
 .. clicmd:: no debug isis events
 
    IS-IS Events.
@@ -566,7 +630,7 @@ Debugging ISIS
 .. index:: debug isis local-updates
 .. clicmd:: debug isis local-updates
 
-.. index:: no debug isis local-updates
+.. index:: debug isis local-updates
 .. clicmd:: no debug isis local-updates
 
    IS-IS local update packets.
@@ -574,7 +638,7 @@ Debugging ISIS
 .. index:: debug isis packet-dump
 .. clicmd:: debug isis packet-dump
 
-.. index:: no debug isis packet-dump
+.. index:: debug isis packet-dump
 .. clicmd:: no debug isis packet-dump
 
    IS-IS packet dump.
@@ -582,7 +646,7 @@ Debugging ISIS
 .. index:: debug isis protocol-errors
 .. clicmd:: debug isis protocol-errors
 
-.. index:: no debug isis protocol-errors
+.. index:: debug isis protocol-errors
 .. clicmd:: no debug isis protocol-errors
 
    IS-IS LSP protocol errors.
@@ -590,7 +654,7 @@ Debugging ISIS
 .. index:: debug isis route-events
 .. clicmd:: debug isis route-events
 
-.. index:: no debug isis route-events
+.. index:: debug isis route-events
 .. clicmd:: no debug isis route-events
 
    IS-IS Route related events.
@@ -598,7 +662,7 @@ Debugging ISIS
 .. index:: debug isis snp-packets
 .. clicmd:: debug isis snp-packets
 
-.. index:: no debug isis snp-packets
+.. index:: debug isis snp-packets
 .. clicmd:: no debug isis snp-packets
 
    IS-IS CSNP/PSNP packets.
@@ -612,13 +676,13 @@ Debugging ISIS
 .. index:: debug isis spf-triggers
 .. clicmd:: debug isis spf-triggers
 
-.. index:: no debug isis spf-events
+.. index:: debug isis spf-events
 .. clicmd:: no debug isis spf-events
 
-.. index:: no debug isis spf-statistics
+.. index:: debug isis spf-statistics
 .. clicmd:: no debug isis spf-statistics
 
-.. index:: no debug isis spf-triggers
+.. index:: debug isis spf-triggers
 .. clicmd:: no debug isis spf-triggers
 
    IS-IS Shortest Path First Events, Timing and Statistic Data and triggering
@@ -627,7 +691,7 @@ Debugging ISIS
 .. index:: debug isis update-packets
 .. clicmd:: debug isis update-packets
 
-.. index:: no debug isis update-packets
+.. index:: debug isis update-packets
 .. clicmd:: no debug isis update-packets
 
    Update related packets.
@@ -635,18 +699,18 @@ Debugging ISIS
 .. index:: debug isis sr-events
 .. clicmd:: debug isis sr-events
 
-.. index:: no debug isis sr-events
+.. index:: debug isis sr-events
 .. clicmd:: no debug isis sr-events
 
    IS-IS Segment Routing events.
 
-.. index:: debug isis ti-lfa
-.. clicmd:: debug isis ti-lfa
+.. index:: debug isis lfa
+.. clicmd:: debug isis lfa
 
-.. index:: no debug isis ti-lfa
-.. clicmd:: no debug isis ti-lfa
+.. index:: debug isis lfa
+.. clicmd:: no debug isis lfa
 
-   IS-IS TI-LFA events.
+   IS-IS LFA events.
 
 .. index:: show debugging isis
 .. clicmd:: show debugging isis
index 2df4ba3005d93d67a9002eb62228dd06045eedca..375842f2ba71475ab59de48e8af065812b9f1bce 100644 (file)
@@ -97,29 +97,29 @@ implementation.
 LDP Configuration
 ===================
 
-.. index:: [no] mpls ldp
+.. index:: mpls ldp
 .. clicmd:: [no] mpls ldp
 
    Enable or disable LDP daemon
 
-.. index:: [no] router-id A.B.C.D
+.. index:: router-id A.B.C.D
 .. clicmd:: [no] router-id A.B.C.D
 
    The following command located under MPLS router node configures the MPLS
    router-id of the local device.
 
-.. index:: [no] ordered-control
+.. index:: ordered-control
 .. clicmd:: [no] ordered-control
 
    Configure LDP Ordered Label Distribution Control.
 
-.. index:: [no] address-family [ipv4 | ipv6]
+.. index:: address-family [ipv4 | ipv6]
 .. clicmd:: [no] address-family [ipv4 | ipv6]
 
    Configure LDP for IPv4 or IPv6 address-family. Located under MPLS route node,
    this subnode permits configuring the LDP neighbors.
 
-.. index:: [no] interface IFACE
+.. index:: interface IFACE
 .. clicmd:: [no] interface IFACE
 
    Located under MPLS address-family node, use this command to enable or disable
@@ -127,14 +127,14 @@ LDP Configuration
    enabled. By default it is disabled. Once this command executed, the
    address-family interface node is configured.
 
-.. index:: [no] discovery transport-address A.B.C.D | A:B::C:D
+.. index:: discovery transport-address A.B.C.D | A:B::C:D
 .. clicmd:: [no] discovery transport-address A.B.C.D | A:B::C:D
 
    Located under mpls address-family interface node, use this command to set
    the IPv4 or IPv6 transport-address used by the LDP protocol to talk on this
    interface.
 
-.. index:: [no] neighbor A.B.C.D password PASSWORD
+.. index:: neighbor A.B.C.D password PASSWORD
 .. clicmd:: [no] neighbor A.B.C.D password PASSWORD
 
    The following command located under MPLS router node configures the router
@@ -142,7 +142,7 @@ LDP Configuration
    configured password. PASSWORD is a clear text password wit its digest sent
    through the network.
 
-.. index:: [no] neighbor A.B.C.D holdtime HOLDTIME
+.. index:: neighbor A.B.C.D holdtime HOLDTIME
 .. clicmd:: [no] neighbor A.B.C.D holdtime HOLDTIME
 
    The following command located under MPLS router node configures the holdtime
@@ -151,10 +151,10 @@ LDP Configuration
    this time of non response, the LDP established session will be considered as
    set to down. By default, no holdtime is configured for the LDP devices.
 
-.. index:: [no] discovery hello holdtime HOLDTIME
+.. index:: discovery hello holdtime HOLDTIME
 .. clicmd:: [no] discovery hello holdtime HOLDTIME
 
-.. index:: [no] discovery hello interval INTERVAL
+.. index:: discovery hello interval INTERVAL
 .. clicmd:: [no] discovery hello interval INTERVAL
 
    INTERVAL value ranges from 1 to 65535 seconds. Default value is 5 seconds.
@@ -162,7 +162,7 @@ LDP Configuration
    HOLDTIME value ranges from 1 to 65535 seconds. Default value is 15 seconds.
    That value is added as a TLV in the LDP messages.
 
-.. index:: [no] dual-stack transport-connection prefer ipv4
+.. index:: dual-stack transport-connection prefer ipv4
 .. clicmd:: [no] dual-stack transport-connection prefer ipv4
 
    When *ldpd* is configured for dual-stack operation, the transport connection
index c66774a4085b6dfe47eec40bfe55ab564f57d312..4f0ff90943f7856e1c1ec5c33034d48fa5a533b3 100644 (file)
@@ -32,7 +32,7 @@ OSPF6 router
 .. index:: timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME
 .. clicmd:: timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME
 
-.. index:: no timers throttle spf
+.. index:: timers throttle spf
 .. clicmd:: no timers throttle spf
 
    This command sets the initial `delay`, the `initial-holdtime`
@@ -71,7 +71,7 @@ OSPF6 router
 .. index:: auto-cost reference-bandwidth COST
 .. clicmd:: auto-cost reference-bandwidth COST
 
-.. index:: no auto-cost reference-bandwidth
+.. index:: auto-cost reference-bandwidth
 .. clicmd:: no auto-cost reference-bandwidth
 
    This sets the reference bandwidth for cost calculations, where this
@@ -163,11 +163,12 @@ Redistribute routes to OSPF6
 Showing OSPF6 information
 =========================
 
-.. index:: show ipv6 ospf6 [INSTANCE_ID]
-.. clicmd:: show ipv6 ospf6 [INSTANCE_ID]
+.. index:: show ipv6 ospf6 [INSTANCE_ID] [json]
+.. clicmd:: show ipv6 ospf6 [INSTANCE_ID] [json]
 
    INSTANCE_ID is an optional OSPF instance ID. To see router ID and OSPF
-   instance ID, simply type "show ipv6 ospf6 <cr>".
+   instance ID, simply type "show ipv6 ospf6 <cr>". JSON output can be
+   obtained by appending 'json' to the end of command.
 
 .. index:: show ipv6 ospf6 database
 .. clicmd:: show ipv6 ospf6 database
@@ -186,6 +187,13 @@ Showing OSPF6 information
    Shows state and chosen (Backup) DR of neighbor. JSON output can be
    obtained by appending 'json' at the end.
 
+.. index:: show ipv6 ospf6 interface traffic [json]
+.. clicmd:: show ipv6 ospf6 interface traffic [json]
+
+   Shows counts of different packets that have been recieved and transmitted
+   by the interfaces. JSON output can be obtained by appending "json" at the
+   end.
+
 .. index:: show ipv6 ospf6 request-list A.B.C.D
 .. clicmd:: show ipv6 ospf6 request-list A.B.C.D
 
@@ -202,6 +210,12 @@ Showing OSPF6 information
    Shows state about what is being redistributed between zebra and OSPF6.
    JSON output can be obtained by appending "json" at the end.
 
+.. index:: show ipv6 ospf6 redistribute [json]
+.. clicmd:: show ipv6 ospf6 redistribute [json]
+
+   Shows the routes which are redistributed by the router. JSON output can
+   be obtained by appending 'json' at the end.
+
 OSPF6 Configuration Examples
 ============================
 
index 31b0df70ae892db6cf4f8f0d8d9f4f40d1c60241..7184a0e19757fc6ccd68c084618a4c5d9c563922 100644 (file)
@@ -83,7 +83,7 @@ To start OSPF process you have to specify the OSPF router.
 .. index:: router ospf [(1-65535)] vrf NAME
 .. clicmd:: router ospf [(1-65535)] vrf NAME
 
-.. index:: no router ospf [(1-65535)] vrf NAME
+.. index:: router ospf [(1-65535)] vrf NAME
 .. clicmd:: no router ospf [(1-65535)] vrf NAME
 
    Enable or disable the OSPF process.
@@ -91,7 +91,7 @@ To start OSPF process you have to specify the OSPF router.
 .. index:: ospf router-id A.B.C.D
 .. clicmd:: ospf router-id A.B.C.D
 
-.. index:: no ospf router-id [A.B.C.D]
+.. index:: ospf router-id [A.B.C.D]
 .. clicmd:: no ospf router-id [A.B.C.D]
 
    This sets the router-ID of the OSPF process. The router-ID may be an IP
@@ -104,7 +104,7 @@ To start OSPF process you have to specify the OSPF router.
 .. index:: ospf abr-type TYPE
 .. clicmd:: ospf abr-type TYPE
 
-.. index:: no ospf abr-type TYPE
+.. index:: ospf abr-type TYPE
 .. clicmd:: no ospf abr-type TYPE
 
    `type` can be cisco|ibm|shortcut|standard. The "Cisco" and "IBM" types
@@ -140,7 +140,7 @@ To start OSPF process you have to specify the OSPF router.
 .. index:: ospf rfc1583compatibility
 .. clicmd:: ospf rfc1583compatibility
 
-.. index:: no ospf rfc1583compatibility
+.. index:: ospf rfc1583compatibility
 .. clicmd:: no ospf rfc1583compatibility
 
    :rfc:`2328`, the successor to :rfc:`1583`, suggests according
@@ -155,7 +155,7 @@ To start OSPF process you have to specify the OSPF router.
 .. index:: log-adjacency-changes [detail]
 .. clicmd:: log-adjacency-changes [detail]
 
-.. index:: no log-adjacency-changes [detail]
+.. index:: log-adjacency-changes [detail]
 .. clicmd:: no log-adjacency-changes [detail]
 
    Configures ospfd to log changes in adjacency. With the optional
@@ -165,7 +165,7 @@ To start OSPF process you have to specify the OSPF router.
 .. index:: passive-interface INTERFACE
 .. clicmd:: passive-interface INTERFACE
 
-.. index:: no passive-interface INTERFACE
+.. index:: passive-interface INTERFACE
 .. clicmd:: no passive-interface INTERFACE
 
    Do not speak OSPF interface on the
@@ -180,7 +180,7 @@ To start OSPF process you have to specify the OSPF router.
 .. index:: timers throttle spf (0-600000) (0-600000) (0-600000)
 .. clicmd:: timers throttle spf (0-600000) (0-600000) (0-600000)
 
-.. index:: no timers throttle spf
+.. index:: timers throttle spf
 .. clicmd:: no timers throttle spf
 
    This command sets the initial `delay`, the `initial-holdtime`
@@ -227,7 +227,7 @@ To start OSPF process you have to specify the OSPF router.
 .. index:: max-metric router-lsa administrative
 .. clicmd:: max-metric router-lsa administrative
 
-.. index:: no max-metric router-lsa [on-startup|on-shutdown|administrative]
+.. index:: max-metric router-lsa [on-startup|on-shutdown|administrative]
 .. clicmd:: no max-metric router-lsa [on-startup|on-shutdown|administrative]
 
    This enables :rfc:`3137` support, where the OSPF process describes its
@@ -260,7 +260,7 @@ To start OSPF process you have to specify the OSPF router.
 .. index:: auto-cost reference-bandwidth (1-4294967)
 .. clicmd:: auto-cost reference-bandwidth (1-4294967)
 
-.. index:: no auto-cost reference-bandwidth
+.. index:: auto-cost reference-bandwidth
 .. clicmd:: no auto-cost reference-bandwidth
 
    This sets the reference
@@ -279,10 +279,10 @@ To start OSPF process you have to specify the OSPF router.
 .. index:: network A.B.C.D/M area (0-4294967295)
 .. clicmd:: network A.B.C.D/M area (0-4294967295)
 
-.. index:: no network A.B.C.D/M area A.B.C.D
+.. index:: network A.B.C.D/M area A.B.C.D
 .. clicmd:: no network A.B.C.D/M area A.B.C.D
 
-.. index:: no network A.B.C.D/M area (0-4294967295)
+.. index:: network A.B.C.D/M area (0-4294967295)
 .. clicmd:: no network A.B.C.D/M area (0-4294967295)
 
    This command specifies the OSPF enabled interface(s). If the interface has
@@ -313,7 +313,7 @@ To start OSPF process you have to specify the OSPF router.
 .. index:: proactive-arp
 .. clicmd:: proactive-arp
 
-.. index:: no proactive-arp
+.. index:: proactive-arp
 .. clicmd:: no proactive-arp
 
    This command enables or disables sending ARP requests to update neighbor
@@ -322,6 +322,23 @@ To start OSPF process you have to specify the OSPF router.
 
    This feature is enabled by default.
 
+.. index:: clear ip ospf [(1-65535)] process
+.. clicmd:: clear ip ospf [(1-65535)] process
+
+   This command can be used to clear the ospf process data structures. This
+   will clear the ospf neighborship as well and it will get re-established.
+   This will clear the LSDB too. This will be helpful when there is a change
+   in router-id and if user wants the router-id change to take effect, user can
+   use this cli instead of restarting the ospfd daemon.
+
+.. index:: clear ip ospf [(1-65535)] neighbor
+.. clicmd:: clear ip ospf [(1-65535)] neighbor
+
+   This command can be used to clear the ospf neighbor data structures. This
+   will clear the ospf neighborship and it will get re-established. This
+   command can be used when the neighbor state get stuck at some state and
+   this can be used to recover it from that state.
+
 .. _ospf-area:
 
 Areas
@@ -333,10 +350,10 @@ Areas
 .. index:: area (0-4294967295) range A.B.C.D/M
 .. clicmd:: area (0-4294967295) range A.B.C.D/M
 
-.. index:: no area A.B.C.D range A.B.C.D/M
+.. index:: area A.B.C.D range A.B.C.D/M
 .. clicmd:: no area A.B.C.D range A.B.C.D/M
 
-.. index:: no area (0-4294967295) range A.B.C.D/M
+.. index:: area (0-4294967295) range A.B.C.D/M
 .. clicmd:: no area (0-4294967295) range A.B.C.D/M
 
    Summarize intra area paths from specified area into one Type-3 summary-LSA
@@ -360,7 +377,7 @@ Areas
 .. index:: area A.B.C.D range IPV4_PREFIX not-advertise
 .. clicmd:: area A.B.C.D range IPV4_PREFIX not-advertise
 
-.. index:: no area A.B.C.D range IPV4_PREFIX not-advertise
+.. index:: area A.B.C.D range IPV4_PREFIX not-advertise
 .. clicmd:: no area A.B.C.D range IPV4_PREFIX not-advertise
 
    Instead of summarizing intra area paths filter them - i.e. intra area paths from this
@@ -370,7 +387,7 @@ Areas
 .. index:: area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX
 .. clicmd:: area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX
 
-.. index:: no area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX
+.. index:: area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX
 .. clicmd:: no area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX
 
    Substitute summarized prefix with another prefix.
@@ -394,10 +411,10 @@ Areas
 .. index:: area (0-4294967295) virtual-link A.B.C.D
 .. clicmd:: area (0-4294967295) virtual-link A.B.C.D
 
-.. index:: no area A.B.C.D virtual-link A.B.C.D
+.. index:: area A.B.C.D virtual-link A.B.C.D
 .. clicmd:: no area A.B.C.D virtual-link A.B.C.D
 
-.. index:: no area (0-4294967295) virtual-link A.B.C.D
+.. index:: area (0-4294967295) virtual-link A.B.C.D
 .. clicmd:: no area (0-4294967295) virtual-link A.B.C.D
 
 .. index:: area A.B.C.D shortcut
@@ -406,10 +423,10 @@ Areas
 .. index:: area (0-4294967295) shortcut
 .. clicmd:: area (0-4294967295) shortcut
 
-.. index:: no area A.B.C.D shortcut
+.. index:: area A.B.C.D shortcut
 .. clicmd:: no area A.B.C.D shortcut
 
-.. index:: no area (0-4294967295) shortcut
+.. index:: area (0-4294967295) shortcut
 .. clicmd:: no area (0-4294967295) shortcut
 
    Configure the area as Shortcut capable. See :rfc:`3509`. This requires
@@ -421,10 +438,10 @@ Areas
 .. index:: area (0-4294967295) stub
 .. clicmd:: area (0-4294967295) stub
 
-.. index:: no area A.B.C.D stub
+.. index:: area A.B.C.D stub
 .. clicmd:: no area A.B.C.D stub
 
-.. index:: no area (0-4294967295) stub
+.. index:: area (0-4294967295) stub
 .. clicmd:: no area (0-4294967295) stub
 
    Configure the area to be a stub area. That is, an area where no router
@@ -440,10 +457,10 @@ Areas
 .. index:: area (0-4294967295) stub no-summary
 .. clicmd:: area (0-4294967295) stub no-summary
 
-.. index:: no area A.B.C.D stub no-summary
+.. index:: area A.B.C.D stub no-summary
 .. clicmd:: no area A.B.C.D stub no-summary
 
-.. index:: no area (0-4294967295) stub no-summary
+.. index:: area (0-4294967295) stub no-summary
 .. clicmd:: no area (0-4294967295) stub no-summary
 
     Prevents an *ospfd* ABR from injecting inter-area
@@ -452,7 +469,7 @@ Areas
 .. index:: area A.B.C.D default-cost (0-16777215)
 .. clicmd:: area A.B.C.D default-cost (0-16777215)
 
-.. index:: no area A.B.C.D default-cost (0-16777215)
+.. index:: area A.B.C.D default-cost (0-16777215)
 .. clicmd:: no area A.B.C.D default-cost (0-16777215)
 
    Set the cost of default-summary LSAs announced to stubby areas.
@@ -463,10 +480,10 @@ Areas
 .. index:: area (0-4294967295) export-list NAME
 .. clicmd:: area (0-4294967295) export-list NAME
 
-.. index:: no area A.B.C.D export-list NAME
+.. index:: area A.B.C.D export-list NAME
 .. clicmd:: no area A.B.C.D export-list NAME
 
-.. index:: no area (0-4294967295) export-list NAME
+.. index:: area (0-4294967295) export-list NAME
 .. clicmd:: no area (0-4294967295) export-list NAME
 
    Filter Type-3 summary-LSAs announced to other areas originated from intra-
@@ -496,10 +513,10 @@ Areas
 .. index:: area (0-4294967295) import-list NAME
 .. clicmd:: area (0-4294967295) import-list NAME
 
-.. index:: no area A.B.C.D import-list NAME
+.. index:: area A.B.C.D import-list NAME
 .. clicmd:: no area A.B.C.D import-list NAME
 
-.. index:: no area (0-4294967295) import-list NAME
+.. index:: area (0-4294967295) import-list NAME
 .. clicmd:: no area (0-4294967295) import-list NAME
 
    Same as export-list, but it applies to paths announced into specified area
@@ -517,16 +534,16 @@ Areas
 .. index:: area (0-4294967295) filter-list prefix NAME out
 .. clicmd:: area (0-4294967295) filter-list prefix NAME out
 
-.. index:: no area A.B.C.D filter-list prefix NAME in
+.. index:: area A.B.C.D filter-list prefix NAME in
 .. clicmd:: no area A.B.C.D filter-list prefix NAME in
 
-.. index:: no area A.B.C.D filter-list prefix NAME out
+.. index:: area A.B.C.D filter-list prefix NAME out
 .. clicmd:: no area A.B.C.D filter-list prefix NAME out
 
-.. index:: no area (0-4294967295) filter-list prefix NAME in
+.. index:: area (0-4294967295) filter-list prefix NAME in
 .. clicmd:: no area (0-4294967295) filter-list prefix NAME in
 
-.. index:: no area (0-4294967295) filter-list prefix NAME out
+.. index:: area (0-4294967295) filter-list prefix NAME out
 .. clicmd:: no area (0-4294967295) filter-list prefix NAME out
 
    Filtering Type-3 summary-LSAs to/from area using prefix lists. This command
@@ -538,10 +555,10 @@ Areas
 .. index:: area (0-4294967295) authentication
 .. clicmd:: area (0-4294967295) authentication
 
-.. index:: no area A.B.C.D authentication
+.. index:: area A.B.C.D authentication
 .. clicmd:: no area A.B.C.D authentication
 
-.. index:: no area (0-4294967295) authentication
+.. index:: area (0-4294967295) authentication
 .. clicmd:: no area (0-4294967295) authentication
 
    Specify that simple password authentication should be used for the given
@@ -569,7 +586,7 @@ Interfaces
 .. index:: ip ospf area AREA [ADDR]
 .. clicmd:: ip ospf area AREA [ADDR]
 
-.. index:: no ip ospf area [ADDR]
+.. index:: ip ospf area [ADDR]
 .. clicmd:: no ip ospf area [ADDR]
 
    Enable OSPF on the interface, optionally restricted to just the IP address
@@ -583,7 +600,7 @@ Interfaces
 .. index:: ip ospf authentication-key AUTH_KEY
 .. clicmd:: ip ospf authentication-key AUTH_KEY
 
-.. index:: no ip ospf authentication-key
+.. index:: ip ospf authentication-key
 .. clicmd:: no ip ospf authentication-key
 
    Set OSPF authentication key to a simple password. After setting `AUTH_KEY`,
@@ -612,7 +629,7 @@ Interfaces
 .. index:: ip ospf message-digest-key KEYID md5 KEY
 .. clicmd:: ip ospf message-digest-key KEYID md5 KEY
 
-.. index:: no ip ospf message-digest-key
+.. index:: ip ospf message-digest-key
 .. clicmd:: no ip ospf message-digest-key
 
    Set OSPF authentication key to a cryptographic password. The cryptographic
@@ -627,7 +644,7 @@ Interfaces
 .. index:: ip ospf cost (1-65535)
 .. clicmd:: ip ospf cost (1-65535)
 
-.. index:: no ip ospf cost
+.. index:: ip ospf cost
 .. clicmd:: no ip ospf cost
 
    Set link cost for the specified interface. The cost value is set to
@@ -639,7 +656,7 @@ Interfaces
 .. index:: ip ospf dead-interval minimal hello-multiplier (2-20)
 .. clicmd:: ip ospf dead-interval minimal hello-multiplier (2-20)
 
-.. index:: no ip ospf dead-interval
+.. index:: ip ospf dead-interval
 .. clicmd:: no ip ospf dead-interval
 
    Set number of seconds for RouterDeadInterval timer value used for Wait Timer
@@ -658,7 +675,7 @@ Interfaces
 .. index:: ip ospf hello-interval (1-65535)
 .. clicmd:: ip ospf hello-interval (1-65535)
 
-.. index:: no ip ospf hello-interval
+.. index:: ip ospf hello-interval
 .. clicmd:: no ip ospf hello-interval
 
    Set number of seconds for HelloInterval timer value. Setting this value,
@@ -679,7 +696,7 @@ Interfaces
    net.ipv4.conf.<interface name>.rp_filter value to 0.  In order for
    the ospf multicast packets to be delivered by the kernel.
 
-.. index:: no ip ospf network
+.. index:: ip ospf network
 .. clicmd:: no ip ospf network
 
    Set explicitly network type for specified interface.
@@ -687,7 +704,7 @@ Interfaces
 .. index:: ip ospf priority (0-255)
 .. clicmd:: ip ospf priority (0-255)
 
-.. index:: no ip ospf priority
+.. index:: ip ospf priority
 .. clicmd:: no ip ospf priority
 
    Set RouterPriority integer value. The router with the highest priority will
@@ -697,7 +714,7 @@ Interfaces
 .. index:: ip ospf retransmit-interval (1-65535)
 .. clicmd:: ip ospf retransmit-interval (1-65535)
 
-.. index:: no ip ospf retransmit interval
+.. index:: ip ospf retransmit interval
 .. clicmd:: no ip ospf retransmit interval
 
    Set number of seconds for RxmtInterval timer value. This value is used when
@@ -707,7 +724,7 @@ Interfaces
 .. index:: ip ospf transmit-delay (1-65535) [A.B.C.D]
 .. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D]
 
-.. index:: no ip ospf transmit-delay [(1-65535)] [A.B.C.D]
+.. index:: ip ospf transmit-delay [(1-65535)] [A.B.C.D]
 .. clicmd:: no ip ospf transmit-delay [(1-65535)] [A.B.C.D]
 
    Set number of seconds for InfTransDelay value. LSAs' age should be
@@ -716,7 +733,7 @@ Interfaces
 .. index:: ip ospf area (A.B.C.D|(0-4294967295))
 .. clicmd:: ip ospf area (A.B.C.D|(0-4294967295))
 
-.. index:: no ip ospf area
+.. index:: ip ospf area
 .. clicmd:: no ip ospf area
 
    Enable ospf on an interface and set associated area.
@@ -762,7 +779,7 @@ Redistribution
 .. index:: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric (0-16777214) route-map WORD
 .. clicmd:: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric (0-16777214) route-map WORD
 
-.. index:: no redistribute (kernel|connected|static|rip|bgp)
+.. index:: redistribute (kernel|connected|static|rip|bgp)
 .. clicmd:: no redistribute (kernel|connected|static|rip|bgp)
 
 .. _ospf-redistribute:
@@ -809,7 +826,7 @@ Redistribution
 .. index:: default-information originate always metric (0-16777214) metric-type (1|2) route-map WORD
 .. clicmd:: default-information originate always metric (0-16777214) metric-type (1|2) route-map WORD
 
-.. index:: no default-information originate
+.. index:: default-information originate
 .. clicmd:: no default-information originate
 
    Originate an AS-External (type-5) LSA describing a default route into all
@@ -820,7 +837,7 @@ Redistribution
 .. index:: distribute-list NAME out (kernel|connected|static|rip|ospf
 .. clicmd:: distribute-list NAME out (kernel|connected|static|rip|ospf
 
-.. index:: no distribute-list NAME out (kernel|connected|static|rip|ospf
+.. index:: distribute-list NAME out (kernel|connected|static|rip|ospf
 .. clicmd:: no distribute-list NAME out (kernel|connected|static|rip|ospf
 
 .. _ospf-distribute-list:
@@ -832,25 +849,25 @@ Redistribution
 .. index:: default-metric (0-16777214)
 .. clicmd:: default-metric (0-16777214)
 
-.. index:: no default-metric
+.. index:: default-metric
 .. clicmd:: no default-metric
 
 .. index:: distance (1-255)
 .. clicmd:: distance (1-255)
 
-.. index:: no distance (1-255)
+.. index:: distance (1-255)
 .. clicmd:: no distance (1-255)
 
 .. index:: distance ospf (intra-area|inter-area|external) (1-255)
 .. clicmd:: distance ospf (intra-area|inter-area|external) (1-255)
 
-.. index:: no distance ospf
+.. index:: distance ospf
 .. clicmd:: no distance ospf
 
 .. index:: router zebra
 .. clicmd:: router zebra
 
-.. index:: no router zebra
+.. index:: router zebra
 .. clicmd:: no router zebra
 
 Graceful Restart Helper
@@ -859,7 +876,7 @@ Graceful Restart Helper
 .. index:: graceful-restart helper-only [A.B.C.D]
 .. clicmd:: graceful-restart helper-only [A.B.C.D]
 
-.. index:: no graceful-restart helper-only [A.B.C.D]
+.. index:: graceful-restart helper-only [A.B.C.D]
 .. clicmd:: no graceful-restart helper-only [A.B.C.D]
 
    Configure Graceful Restart (RFC 3623) helper support.
@@ -872,7 +889,7 @@ Graceful Restart Helper
 .. index:: graceful-restart helper strict-lsa-checking
 .. clicmd:: graceful-restart helper strict-lsa-checking
 
-.. index:: no graceful-restart helper strict-lsa-checking
+.. index:: graceful-restart helper strict-lsa-checking
 .. clicmd:: no graceful-restart helper strict-lsa-checking
 
    If 'strict-lsa-checking' is configured then the helper will
@@ -883,7 +900,7 @@ Graceful Restart Helper
 .. index:: graceful-restart helper supported-grace-time
 .. clicmd:: graceful-restart helper supported-grace-time
 
-.. index:: no graceful-restart helper supported-grace-time
+.. index:: graceful-restart helper supported-grace-time
 .. clicmd:: no graceful-restart helper supported-grace-time
 
    Supports as HELPER for configured grace period.
@@ -891,7 +908,7 @@ Graceful Restart Helper
 .. index:: graceful-restart helper planned-only
 .. clicmd:: graceful-restart helper planned-only
 
-.. index:: no graceful-restart helper planned-only
+.. index:: graceful-restart helper planned-only
 .. clicmd:: no graceful-restart helper planned-only
 
    It helps to support as HELPER only for planned
@@ -983,10 +1000,10 @@ Opaque LSA
 .. index:: capability opaque
 .. clicmd:: capability opaque
 
-.. index:: no ospf opaque-lsa
+.. index:: ospf opaque-lsa
 .. clicmd:: no ospf opaque-lsa
 
-.. index:: no capability opaque
+.. index:: capability opaque
 .. clicmd:: no capability opaque
 
    *ospfd* supports Opaque LSA (:rfc:`2370`) as partial support for
@@ -1031,7 +1048,7 @@ Traffic Engineering
 .. index:: mpls-te on
 .. clicmd:: mpls-te on
 
-.. index:: no mpls-te
+.. index:: mpls-te
 .. clicmd:: no mpls-te
 
    Enable Traffic Engineering LSA flooding.
@@ -1045,7 +1062,7 @@ Traffic Engineering
 .. index:: mpls-te inter-as area <area-id>|as
 .. clicmd:: mpls-te inter-as area <area-id>|as
 
-.. index:: no mpls-te inter-as
+.. index:: mpls-te inter-as
 .. clicmd:: no mpls-te inter-as
 
    Enable :rfc:`5392` support - Inter-AS TE v2 - to flood Traffic Engineering
@@ -1074,7 +1091,7 @@ Router Information
 .. index:: router-info [as | area]
 .. clicmd:: router-info [as | area]
 
-.. index:: no router-info
+.. index:: router-info
 .. clicmd:: no router-info
 
    Enable Router Information (:rfc:`4970`) LSA advertisement with AS scope
@@ -1086,31 +1103,31 @@ Router Information
 .. index:: pce address <A.B.C.D>
 .. clicmd:: pce address <A.B.C.D>
 
-.. index:: no pce address
+.. index:: pce address
 .. clicmd:: no pce address
 
 .. index:: pce domain as (0-65535)
 .. clicmd:: pce domain as (0-65535)
 
-.. index:: no pce domain as (0-65535)
+.. index:: pce domain as (0-65535)
 .. clicmd:: no pce domain as (0-65535)
 
 .. index:: pce neighbor as (0-65535)
 .. clicmd:: pce neighbor as (0-65535)
 
-.. index:: no pce neighbor as (0-65535)
+.. index:: pce neighbor as (0-65535)
 .. clicmd:: no pce neighbor as (0-65535)
 
 .. index:: pce flag BITPATTERN
 .. clicmd:: pce flag BITPATTERN
 
-.. index:: no pce flag
+.. index:: pce flag
 .. clicmd:: no pce flag
 
 .. index:: pce scope BITPATTERN
 .. clicmd:: pce scope BITPATTERN
 
-.. index:: no pce scope
+.. index:: pce scope
 .. clicmd:: no pce scope
 
    The commands are conform to :rfc:`5088` and allow OSPF router announce Path
@@ -1139,32 +1156,32 @@ Segment Routing
 This is an EXPERIMENTAL support of Segment Routing as per `RFC 8665` for MPLS
 dataplane.
 
-.. index:: [no] segment-routing on
+.. index:: segment-routing on
 .. clicmd:: [no] segment-routing on
 
    Enable Segment Routing. Even if this also activate routing information
    support, it is preferable to also activate routing information, and set
    accordingly the Area or AS flooding.
 
-.. index:: [no] segment-routing global-block (0-1048575) (0-1048575)
+.. index:: segment-routing global-block (0-1048575) (0-1048575)
 .. clicmd:: [no] segment-routing global-block (0-1048575) (0-1048575)
 
    Fix the Segment Routing Global Block i.e. the label range used by MPLS to
    store label in the MPLS FIB for Prefix SID.
 
-.. index:: [no] segment-routing local-block (0-1048575) (0-1048575)
+.. index:: segment-routing local-block (0-1048575) (0-1048575)
 .. clicmd:: [no] segment-routing local-block (0-1048575) (0-1048575)
 
    Fix the Segment Routing Local Block i.e. the label range used by MPLS to
    store label in the MPLS FIB for Adjacency SID.
 
-.. index:: [no] segment-routing node-msd (1-16)
+.. index:: segment-routing node-msd (1-16)
 .. clicmd:: [no] segment-routing node-msd (1-16)
 
    Fix the Maximum Stack Depth supported by the router. The value depend of the
    MPLS dataplane. E.g. for Linux kernel, since version 4.13 it is 32.
 
-.. index:: [no] segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag|explicit-null]
+.. index:: segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag|explicit-null]
 .. clicmd:: [no] segment-routing prefix A.B.C.D/M [index (0-65535)|no-php-flag|explicit-null]
 
    Set the Segment Routing index for the specified prefix. Note that, only
@@ -1186,14 +1203,14 @@ External Route Summarisation
 This feature summarises originated external LSAs(Type-5 and Type-7).
 Summary Route will be originated on-behalf of all matched external LSAs.
 
-.. index:: [no] summary-address A.B.C.D/M [tag (1-4294967295)]
+.. index:: summary-address A.B.C.D/M [tag (1-4294967295)]
 .. clicmd:: [no] summary-address A.B.C.D/M [tag (1-4294967295)]
 
    This command enable/disables summarisation for the configured address
    range. Tag is the optional parameter. If tag configured Summary route
    will be originated with the configured tag.
 
-.. index:: [no] summary-address A.B.C.D/M no-advertise
+.. index:: summary-address A.B.C.D/M no-advertise
 .. clicmd:: [no] summary-address A.B.C.D/M no-advertise
 
    This command to ensure not advertise the summary lsa for the matched
@@ -1205,7 +1222,7 @@ Summary Route will be originated on-behalf of all matched external LSAs.
    Configure aggregation delay timer interval. Summarisation starts only after
    this delay timer expiry. By default, delay interval is 5 secs.
 
-.. index:: no aggregation timer
+.. index:: aggregation timer
 .. clicmd:: no aggregation timer
 
    Resetting the aggregation delay interval to default value.
@@ -1222,7 +1239,7 @@ Debugging OSPF
 .. index:: debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]
 .. clicmd:: debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]
 
-.. index:: no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]
+.. index:: debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]
 .. clicmd:: no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]
 
    Dump Packet for debugging
@@ -1233,10 +1250,10 @@ Debugging OSPF
 .. index:: debug ospf ism (status|events|timers)
 .. clicmd:: debug ospf ism (status|events|timers)
 
-.. index:: no debug ospf ism
+.. index:: debug ospf ism
 .. clicmd:: no debug ospf ism
 
-.. index:: no debug ospf ism (status|events|timers)
+.. index:: debug ospf ism (status|events|timers)
 .. clicmd:: no debug ospf ism (status|events|timers)
 
    Show debug information of Interface State Machine
@@ -1247,10 +1264,10 @@ Debugging OSPF
 .. index:: debug ospf nsm (status|events|timers)
 .. clicmd:: debug ospf nsm (status|events|timers)
 
-.. index:: no debug ospf nsm
+.. index:: debug ospf nsm
 .. clicmd:: no debug ospf nsm
 
-.. index:: no debug ospf nsm (status|events|timers)
+.. index:: debug ospf nsm (status|events|timers)
 .. clicmd:: no debug ospf nsm (status|events|timers)
 
    Show debug information of Network State Machine
@@ -1258,7 +1275,7 @@ Debugging OSPF
 .. index:: debug ospf event
 .. clicmd:: debug ospf event
 
-.. index:: no debug ospf event
+.. index:: debug ospf event
 .. clicmd:: no debug ospf event
 
    Show debug information of OSPF event
@@ -1266,7 +1283,7 @@ Debugging OSPF
 .. index:: debug ospf nssa
 .. clicmd:: debug ospf nssa
 
-.. index:: no debug ospf nssa
+.. index:: debug ospf nssa
 .. clicmd:: no debug ospf nssa
 
    Show debug information about Not So Stub Area
@@ -1277,10 +1294,10 @@ Debugging OSPF
 .. index:: debug ospf lsa (generate|flooding|refresh)
 .. clicmd:: debug ospf lsa (generate|flooding|refresh)
 
-.. index:: no debug ospf lsa
+.. index:: debug ospf lsa
 .. clicmd:: no debug ospf lsa
 
-.. index:: no debug ospf lsa (generate|flooding|refresh)
+.. index:: debug ospf lsa (generate|flooding|refresh)
 .. clicmd:: no debug ospf lsa (generate|flooding|refresh)
 
    Show debug detail of Link State messages
@@ -1288,7 +1305,7 @@ Debugging OSPF
 .. index:: debug ospf te
 .. clicmd:: debug ospf te
 
-.. index:: no debug ospf te
+.. index:: debug ospf te
 .. clicmd:: no debug ospf te
 
    Show debug information about Traffic Engineering LSA
@@ -1299,10 +1316,10 @@ Debugging OSPF
 .. index:: debug ospf zebra (interface|redistribute)
 .. clicmd:: debug ospf zebra (interface|redistribute)
 
-.. index:: no debug ospf zebra
+.. index:: debug ospf zebra
 .. clicmd:: no debug ospf zebra
 
-.. index:: no debug ospf zebra (interface|redistribute)
+.. index:: debug ospf zebra (interface|redistribute)
 .. clicmd:: no debug ospf zebra (interface|redistribute)
 
    Show debug information of ZEBRA API
@@ -1310,7 +1327,7 @@ Debugging OSPF
 .. index:: debug ospf graceful-restart helper
 .. clicmd:: debug ospf graceful-restart helper
 
-.. index:: no debug ospf graceful-restart helper
+.. index:: debug ospf graceful-restart helper
 .. clicmd:: no debug ospf graceful-restart helper
 
    Enable/disable debug information for OSPF Graceful Restart Helper
@@ -1318,7 +1335,7 @@ Debugging OSPF
 .. index:: show debugging ospf
 .. clicmd:: show debugging ospf
 
-.. index:: [no] debug ospf lsa aggregate
+.. index:: debug ospf lsa aggregate
 .. clicmd:: [no] debug ospf lsa aggregate
 
    Debug commnd to enable/disable external route summarisation specific debugs.
index 07702cbdd1fff7d107e148c3d81378f3c5f80bda..f67698e4046efe535d2f9d845d37a09f7be1a298 100644 (file)
@@ -109,9 +109,9 @@ daemons using a single configuration file through the integrated configuration
 mode. This avoids the overhead of maintaining a separate configuration file for
 each daemon.
 
-FRR is currently currently implementing a new internal configuration system
-based on YANG data models. When this work is completed, FRR will be a fully
-programmable routing stack.
+FRR is currently implementing a new internal configuration system based on YANG
+data models. When this work is completed, FRR will be a fully programmable
+routing stack.
 
 
 .. _supported-platforms:
@@ -321,6 +321,8 @@ BGP
   :t:`The Resource Public Key Infrastructure (RPKI) to Router Protocol. R. Bush, R. Austein. January 2013.`
 - :rfc:`6811`
   :t:`BGP Prefix Origin Validation. P. Mohapatra, J. Scudder, D. Ward, R. Bush, R. Austein. January 2013.`
+- :rfc:`7313`
+  :t:`Enhanced Route Refresh Capability for BGP-4. K. Patel, E. Chen, B. Venkatachalapathy. July 2014.`
 - :rfc:`7606`
   :t:`Revised Error Handling for BGP UPDATE Messages. E. Chen, J. Scudder, P. Mohapatra, K. Patel. August 2015.`
 - :rfc:`7607`
diff --git a/doc/user/pathd.rst b/doc/user/pathd.rst
new file mode 100644 (file)
index 0000000..0815a6c
--- /dev/null
@@ -0,0 +1,443 @@
+.. _path:
+
+****
+PATH
+****
+
+:abbr:`PATH` is a daemon that handles the installation and deletion
+of Segment Routing (SR) Policies.
+
+
+.. _starting-path:
+
+Starting PATH
+=============
+
+Default configuration file for *pathd* is :file:`pathd.conf`.  The typical
+location of :file:`pathd.conf` is |INSTALL_PREFIX_ETC|/pathd.conf.
+
+If the user is using integrated config, then :file:`pathd.conf` need not be
+present and the :file:`frr.conf` is read instead.
+
+.. program:: pathd
+
+:abbr:`PATH` supports all the common FRR daemon start options which are
+documented elsewhere.
+
+
+PCEP Support
+============
+
+To build the PCC for pathd, the externall library `pceplib 1.2 <https://github.com/volta-networks/pceplib/tree/devel-1.2>`_ is required.
+
+To build FRR with support for PCEP the following steps must be followed:
+
+ - Checkout and build pceplib:
+
+```
+$ git clone https://github.com/volta-networks/pceplib
+$ cd pceplib
+$ make
+$ make install
+$ export PCEPLIB_ROOT=$PWD
+```
+
+ - Configure FRR with the extra parameters:
+
+```
+--enable-pcep LDFLAGS="-L${PCEPLIB_ROOT}/install/lib" CPPFLAGS="-I${PCEPLIB_ROOT}/install/include"
+```
+
+To start pathd with pcep support the extra parameter `-M pathd_pcep` should be
+passed to the pathd daemon.
+
+
+Pathd Configuration
+===================
+
+Example:
+
+.. code-block:: frr
+
+  debug pathd pcep basic
+  segment-routing
+   traffic-eng
+    segment-list SL1
+     index 10 mpls label 16010
+     index 20 mpls label 16030
+    !
+    policy color 1 endpoint 1.1.1.1
+     name default
+     binding-sid 4000
+     candidate-path preference 100 name CP1 explicit segment-list SL1
+     candidate-path preference 200 name CP2 dynamic
+      affinity include-any 0x000000FF
+      bandwidth 100000
+      metric bound msd 16 required
+      metric te 10
+      objective-function mcp required
+    !
+    pcep
+     pce-config GROUP1
+      source-address 1.1.1.1
+      tcp-md5-auth secret
+      timer keep-alive 30
+     !
+     pce PCE1
+      config GROUP1
+      address ip 10.10.10.10
+     !
+     pce PCE2
+      config GROUP1
+      address ip 9.9.9.9
+     !
+     pcc
+      peer PCE1 precedence 10
+      peer PCE2 precedence 20
+     !
+    !
+   !
+  !
+
+
+.. _path-commands:
+
+Configuration Commands
+----------------------
+
+.. index:: segment-routing
+.. clicmd:: segment-routing
+
+   Configure segment routing.
+
+.. index:: traffic-eng
+.. clicmd:: traffic-eng
+
+   Configure segment routing traffic engineering.
+
+.. index:: segment-list NAME
+.. clicmd:: [no] segment-list NAME
+
+   Delete or start a segment list definition.
+
+
+.. index:: index INDEX mpls label LABEL [nai node ADDRESS]
+.. clicmd:: [no] index INDEX mpls label LABEL [nai node ADDRESS]
+
+   Delete or specify a segment in a segment list definition.
+
+
+.. index:: policy color COLOR endpoint ENDPOINT
+.. clicmd:: [no] policy color COLOR endpoint ENDPOINT
+
+   Delete or start a policy definition.
+
+
+.. index:: name NAME
+.. clicmd:: name NAME
+
+   Specify the policy name.
+
+
+.. index:: binding-sid LABEL
+.. clicmd:: binding-sid LABEL
+
+   Specify the policy SID.
+
+
+.. index:: candidate-path preference PREFERENCE name NAME explicit segment-list SEGMENT-LIST-NAME
+.. clicmd:: [no] candidate-path preference PREFERENCE name NAME explicit segment-list SEGMENT-LIST-NAME
+
+   Delete or define an explicit candidate path.
+
+
+.. index:: candidate-path preference PREFERENCE name NAME dynamic
+.. clicmd:: [no] candidate-path preference PREFERENCE name NAME dynamic
+
+   Delete or start a dynamic candidate path definition.
+
+
+.. index:: affinity {exclude-any|include-any|include-all} BITPATTERN
+.. clicmd:: [no] affinity {exclude-any|include-any|include-all} BITPATTERN
+
+   Delete or specify an affinity constraint for a dynamic candidate path.
+
+
+.. index:: bandwidth BANDWIDTH [required]
+.. clicmd:: [no] bandwidth BANDWIDTH [required]
+
+   Delete or specify a bandwidth constraint for a dynamic candidate path.
+
+
+.. index:: metric [bound] METRIC VALUE [required]
+.. clicmd:: [no] metric [bound] METRIC VALUE [required]
+
+   Delete or specify a metric constraint for a dynamic candidate path.
+
+   The possible metrics are:
+    - igp: IGP metric
+    - te: TE metric
+    - hc: Hop Counts
+    - abc: Aggregate bandwidth consumption
+    - mll: Load of the most loaded link
+    - igp: Cumulative IGP cost
+    - cte: Cumulative TE cost
+    - igp: P2MP IGP metric
+    - pte: P2MP TE metric
+    - phc: P2MP hop count metric
+    - msd: Segment-ID (SID) Depth
+    - pd: Path Delay metric
+    - pdv: Path Delay Variation metric
+    - pl: Path Loss metric
+    - ppd: P2MP Path Delay metric
+    - pdv: P2MP Path Delay variation metric
+    - ppl: P2MP Path Loss metric
+    - nap: Number of adaptations on a path
+    - nlp: Number of layers on a path
+    - dc: Domain Count metric
+    - bnc: Border Node Count metric
+
+
+.. index:: objective-function OBJFUN1 [required]
+.. clicmd:: [no] objective-function OBJFUN1 [required]
+
+   Delete or specify a PCEP objective function constraint for a dynamic
+   candidate path.
+
+   The possible functions are:
+     - mcp: Minimum Cost Path [RFC5541]
+     - mlp: Minimum Load Path [RFC5541]
+     - mbp: Maximum residual Bandwidth Path [RFC5541]
+     - mbc: Minimize aggregate Bandwidth Consumption [RFC5541]
+     - mll: Minimize the Load of the most loaded Link [RFC5541]
+     - mcc: Minimize the Cumulative Cost of a set of paths [RFC5541]
+     - spt: Shortest Path Tree [RFC8306]
+     - mct: Minimum Cost Tree [RFC8306]
+     - mplp: Minimum Packet Loss Path [RFC8233]
+     - mup: Maximum Under-Utilized Path [RFC8233]
+     - mrup: Maximum Reserved Under-Utilized Path [RFC8233]
+     - mtd: Minimize the number of Transit Domains [RFC8685]
+     - mbn: Minimize the number of Border Nodes [RFC8685]
+     - mctd: Minimize the number of Common Transit Domains [RFC8685]
+     - msl: Minimize the number of Shared Links [RFC8800]
+     - mss: Minimize the number of Shared SRLGs [RFC8800]
+     - msn: Minimize the number of Shared Nodes [RFC8800]
+
+
+.. index:: debug pathd pcep [basic|path|message|pceplib]
+.. clicmd:: [no] debug pathd pcep [basic|path|message|pceplib]
+
+   Enable or disable debugging for the pcep module:
+
+     - basic: Enable basic PCEP logging
+     - path: Log the path structures
+     - message: Log the PCEP messages
+     - pceplib: Enable pceplib logging
+
+
+.. index:: pcep
+.. clicmd:: pcep
+
+   Configure PCEP support.
+
+
+.. index:: cep-config NAME
+.. clicmd:: [no] pce-config NAME
+
+   Define a shared PCE configuration that can be used in multiple PCE
+   declarations.
+
+
+.. index:: pce NAME
+.. clicmd:: [no] pce NAME
+
+   Define or delete a PCE definition.
+
+
+.. index:: config WORD
+.. clicmd:: config WORD
+
+   Select a shared configuration. If not defined, the default
+   configuration will be used.
+
+
+.. index:: address <ip A.B.C.D | ipv6 X:X::X:X> [port (1024-65535)]
+.. clicmd:: address <ip A.B.C.D | ipv6 X:X::X:X> [port (1024-65535)]
+
+   Define the address and port of the PCE.
+
+   If not specified, the port is the standard PCEP port 4189.
+
+   This should be specified in the PCC peer definition.
+
+
+.. index:: source-address [ip A.B.C.D | ipv6 X:X::X:X] [port PORT]
+.. clicmd:: source-address [ip A.B.C.D | ipv6 X:X::X:X] [port PORT]
+
+   Define the address and/or port of the PCC as seen by the PCE.
+   This can be used in a configuration group or a PCC peer declaration.
+
+   If not specified, the source address will be the router identifier selected
+   by zebra, and the port will be the standard PCEP port 4189.
+
+   This can be specified in either the PCC peer definition or in a
+   configuration group.
+
+
+.. index:: tcp-md5-auth WORD
+.. clicmd:: tcp-md5-auth WORD
+
+   Enable TCP MD5 security with the given secret.
+
+   This can be specified in either the PCC peer definition or in a
+   configuration group.
+
+
+.. index:: sr-draft07
+.. clicmd:: sr-draft07
+
+   Specify if a PCE only support segment routing draft 7, this flag will limit
+   the PCC behavior to this draft.
+
+   This can be specified in either the PCC peer definition or in a
+   configuration group.
+
+
+.. index:: pce-initiated
+.. clicmd:: pce-initiated
+
+   Specify if PCE-initiated LSP should be allowed for this PCE.
+
+   This can be specified in either the PCC peer definition or in a
+   configuration group.
+
+
+.. index:: timer [keep-alive (1-63)] [min-peer-keep-alive (1-255)] [max-peer-keep-alive (1-255)] [dead-timer (4-255)] [min-peer-dead-timer (4-255)] [max-peer-dead-timer (4-255)] [pcep-request (1-120)] [session-timeout-interval (1-120)] [delegation-timeout (1-60)]
+.. clicmd:: timer [keep-alive (1-63)] [min-peer-keep-alive (1-255)] [max-peer-keep-alive (1-255)] [dead-timer (4-255)] [min-peer-dead-timer (4-255)] [max-peer-dead-timer (4-255)] [pcep-request (1-120)] [session-timeout-interval (1-120)] [delegation-timeout (1-60)]
+
+   Specify the PCEP timers.
+
+   This can be specified in either the PCC peer definition or in a
+   configuration group.
+
+
+.. index:: pcc
+.. clicmd:: [no] pcc
+
+   Disable or start the definition of a PCC.
+
+
+.. index:: msd (1-32)
+.. clicmd:: msd (1-32)
+
+   Specify the maximum SID depth in a PCC definition.
+
+
+.. index:: peer WORD [precedence (1-255)]
+.. clicmd:: [no] peer WORD [precedence (1-255)]
+
+   Specify a peer and its precedence in a PCC definition.
+
+
+Introspection Commands
+----------------------
+
+.. index:: show sr-te policy [detail]
+.. clicmd:: show sr-te policy [detail]
+
+   Display the segment routing policies.
+
+.. code-block:: frr
+
+  router# show sr-te policy
+
+   Endpoint  Color  Name     BSID  Status
+   ------------------------------------------
+   1.1.1.1   1      default  4000  Active
+
+
+.. code-block:: frr
+
+  router# show sr-te policy detail
+
+  Endpoint: 1.1.1.1  Color: 1  Name: LOW_DELAY  BSID: 4000  Status: Active
+      Preference: 100  Name: cand1  Type: explicit  Segment-List: sl1  Protocol-Origin: Local
+    * Preference: 200  Name: cand1  Type: dynamic  Segment-List: 32453452  Protocol-Origin: PCEP
+
+The asterisk (*) marks the best, e.g. active, candidate path. Note that for segment-lists which are
+retrieved via PCEP a random number based name is generated.
+
+
+.. index:: show debugging pathd
+.. clicmd:: show debugging pathd
+
+   Display the current status of the pathd debugging.
+
+
+.. index:: show debugging pathd-pcep
+.. clicmd:: show debugging pathd-pcep
+
+   Display the current status of the pcep module debugging.
+
+
+.. index:: show sr-te pcep counters
+.. clicmd:: show sr-te pcep counters
+
+   Display the counters from pceplib.
+
+
+.. index:: show sr-te pcep pce-config [NAME]
+.. clicmd:: show sr-te pcep pce-config [NAME]
+
+   Display a shared configuration. if no name is specified, the default
+   configuration will be displayed.
+
+
+.. index:: show sr-te pcep pcc
+.. clicmd:: show sr-te pcep pcc
+
+   Display PCC information.
+
+
+.. index:: show sr-te pcep session [NAME]
+.. clicmd:: show sr-te pcep session [NAME]
+
+   Display the information of a PCEP session, if not name is specified all the
+   sessions will be displayed.
+
+
+Utility Commands
+----------------
+
+.. index:: clear sr-te pcep session [NAME]
+.. clicmd:: clear sr-te pcep session [NAME]
+
+   Reset the pcep session by disconnecting from the PCE and performing the
+   normal reconnection process. No configuration is changed.
+
+
+Usage with BGP route-maps
+=========================
+
+It is possible to steer traffic 'into' a segment routing policy for routes
+learned through BGP using route-maps:
+
+.. code-block:: frr
+
+  route-map SET_SR_POLICY permit 10
+   set sr-te color 1
+  !
+  router bgp 1
+   bgp router-id 2.2.2.2
+   neighbor 1.1.1.1 remote-as 1
+   neighbor 1.1.1.1 update-source lo
+   !
+   address-family ipv4 unicast
+    neighbor 1.1.1.1 next-hop-self
+    neighbor 1.1.1.1 route-map SET_SR_POLICY in
+    redistribute static
+   exit-address-family
+   !
+  !
+
+In this case, the SR Policy with color `1` and endpoint `1.1.1.1` is selected.
index b0a90bfc48fc3c42fd4b3cdc50b9569328f10e38..05297a0609c219d62d95bc3df88a23d1062d2efe 100644 (file)
@@ -166,18 +166,18 @@ Certain signals have special meanings to *pimd*.
    urib-only
       Lookup in the Unicast Rib only.
 
-.. index:: [no] ip msdp mesh-group [WORD]
+.. index:: ip msdp mesh-group [WORD]
 .. clicmd:: [no] ip msdp mesh-group [WORD]
 
    Create or Delete a multicast source discovery protocol mesh-group using
    [WORD] as the group name.
 
-.. index:: [no] ip msdp mesh-group WORD member A.B.C.D
+.. index:: ip msdp mesh-group WORD member A.B.C.D
 .. clicmd:: [no] ip msdp mesh-group WORD member A.B.C.D
 
    Attach or Delete A.B.C.D to the MSDP mesh group WORD specified.
 
-.. index:: [no] ip msdp mesh-group WORD source A.B.C.D
+.. index:: ip msdp mesh-group WORD source A.B.C.D
 .. clicmd:: [no] ip msdp mesh-group WORD source A.B.C.D
 
    For the address specified A.B.C.D use that as the source address for
@@ -190,7 +190,7 @@ Certain signals have special meanings to *pimd*.
    the existing IGMP general query timer.If no version is provided in the cli,
    it will be considered as default v2 query.This is a hidden command.
 
-.. index:: [no] ip igmp watermark-warn (10-60000)
+.. index:: ip igmp watermark-warn (10-60000)
 .. clicmd:: [no] ip igmp watermark-warn (10-60000)
 
    Configure watermark warning generation for an igmp group limit. Generates
@@ -252,7 +252,7 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
    reports on the interface. Refer to the next `ip igmp` command for IGMP
    management.
 
-.. index:: [no] ip pim use-source A.B.C.D
+.. index:: ip pim use-source A.B.C.D
 .. clicmd:: [no] ip pim use-source A.B.C.D
 
    If you have multiple addresses configured on a particular interface
@@ -358,17 +358,17 @@ Multicast Source Discovery Protocol (MSDP) Configuration
 
    Establish a MSDP connection with a peer.
 
-.. index:: no ip msdp mesh-group [WORD] member A.B.C.D
+.. index:: ip msdp mesh-group [WORD] member A.B.C.D
 .. clicmd:: no ip msdp mesh-group [WORD] member A.B.C.D
 
    Remove a MSDP peer member from a MSDP mesh-group.
 
-.. index:: no ip msdp mesh-group [WORD] source A.B.C.D
+.. index:: ip msdp mesh-group [WORD] source A.B.C.D
 .. clicmd:: no ip msdp mesh-group [WORD] source A.B.C.D
 
    Delete a MSDP mesh-group.
 
-.. index:: no ip msdp peer A.B.C.D
+.. index:: ip msdp peer A.B.C.D
 .. clicmd:: no ip msdp peer A.B.C.D
 
    Delete a MSDP peer connection.
@@ -726,6 +726,13 @@ Clear commands reset various variables.
 
    Rescan PIM OIL (output interface list).
 
+.. index:: clear ip pim [vrf NAME] bsr-data
+.. clicmd:: clear ip pim [vrf NAME] bsr-data
+
+   This command will clear the BSM scope data struct. This command also
+   removes the next hop tracking for the bsr and resets the upstreams
+   for the dynamically learnt RPs.
+
 PIM EVPN configuration
 ======================
 To use PIM in the underlay for overlay BUM forwarding associate a multicast
index 372c30f58766468e5be3860fafd21daee548aab3..e83b505a191f90d63893f249971380c551195d40 100644 (file)
@@ -94,7 +94,7 @@ RIP Configuration
    `no router rip` command. RIP must be enabled before carrying out any of the
    RIP commands.
 
-.. index:: no router rip
+.. index:: router rip
 .. clicmd:: no router rip
 
    Disable RIP.
@@ -102,7 +102,7 @@ RIP Configuration
 .. index:: network NETWORK
 .. clicmd:: network NETWORK
 
-.. index:: no network NETWORK
+.. index:: network NETWORK
 .. clicmd:: no network NETWORK
 
    Set the RIP enable interface by NETWORK. The interfaces which have addresses
@@ -117,7 +117,7 @@ RIP Configuration
 .. index:: network IFNAME
 .. clicmd:: network IFNAME
 
-.. index:: no network IFNAME
+.. index:: network IFNAME
 .. clicmd:: no network IFNAME
 
    Set a RIP enabled interface by IFNAME. Both the sending and
@@ -128,7 +128,7 @@ RIP Configuration
 .. index:: neighbor A.B.C.D
 .. clicmd:: neighbor A.B.C.D
 
-.. index:: no neighbor A.B.C.D
+.. index:: neighbor A.B.C.D
 .. clicmd:: no neighbor A.B.C.D
 
    Specify RIP neighbor. When a neighbor doesn't understand multicast, this
@@ -155,7 +155,7 @@ RIP Configuration
 .. index:: passive-interface (IFNAME|default)
 .. clicmd:: passive-interface (IFNAME|default)
 
-.. index:: no passive-interface IFNAME
+.. index:: passive-interface IFNAME
 .. clicmd:: no passive-interface IFNAME
 
    This command sets the specified interface to passive mode. On passive mode
@@ -169,7 +169,7 @@ RIP Configuration
 .. index:: ip split-horizon
 .. clicmd:: ip split-horizon
 
-.. index:: no ip split-horizon
+.. index:: ip split-horizon
 .. clicmd:: no ip split-horizon
 
    Control split-horizon on the interface. Default is `ip split-horizon`. If
@@ -203,7 +203,7 @@ discussion on the security implications of RIPv1 see :ref:`rip-authentication`.
 
    Default: Send Version 2, and accept either version.
 
-.. index:: no version
+.. index:: version
 .. clicmd:: no version
 
    Reset the global version setting back to the default.
@@ -246,7 +246,7 @@ How to Announce RIP route
 .. index:: redistribute kernel route-map ROUTE-MAP
 .. clicmd:: redistribute kernel route-map ROUTE-MAP
 
-.. index:: no redistribute kernel
+.. index:: redistribute kernel
 .. clicmd:: no redistribute kernel
 
    `redistribute kernel` redistributes routing information from kernel route
@@ -261,7 +261,7 @@ How to Announce RIP route
 .. index:: redistribute static route-map ROUTE-MAP
 .. clicmd:: redistribute static route-map ROUTE-MAP
 
-.. index:: no redistribute static
+.. index:: redistribute static
 .. clicmd:: no redistribute static
 
    `redistribute static` redistributes routing information from static route
@@ -276,7 +276,7 @@ How to Announce RIP route
 .. index:: redistribute connected route-map ROUTE-MAP
 .. clicmd:: redistribute connected route-map ROUTE-MAP
 
-.. index:: no redistribute connected
+.. index:: redistribute connected
 .. clicmd:: no redistribute connected
 
    Redistribute connected routes into the RIP tables. `no redistribute
@@ -293,7 +293,7 @@ How to Announce RIP route
 .. index:: redistribute ospf route-map ROUTE-MAP
 .. clicmd:: redistribute ospf route-map ROUTE-MAP
 
-.. index:: no redistribute ospf
+.. index:: redistribute ospf
 .. clicmd:: no redistribute ospf
 
    `redistribute ospf` redistributes routing information from ospf route
@@ -308,7 +308,7 @@ How to Announce RIP route
 .. index:: redistribute bgp route-map ROUTE-MAP
 .. clicmd:: redistribute bgp route-map ROUTE-MAP
 
-.. index:: no redistribute bgp
+.. index:: redistribute bgp
 .. clicmd:: no redistribute bgp
 
    `redistribute bgp` redistributes routing information from bgp route entries
@@ -322,7 +322,7 @@ How to Announce RIP route
 .. index:: route A.B.C.D/M
 .. clicmd:: route A.B.C.D/M
 
-.. index:: no route A.B.C.D/M
+.. index:: route A.B.C.D/M
 .. clicmd:: no route A.B.C.D/M
 
    This command is specific to FRR. The `route` command makes a static route
@@ -384,7 +384,7 @@ received. Redistributed routes' metric is set to 1.
 .. index:: default-metric (1-16)
 .. clicmd:: default-metric (1-16)
 
-.. index:: no default-metric (1-16)
+.. index:: default-metric (1-16)
 .. clicmd:: no default-metric (1-16)
 
    This command modifies the default metric value for redistributed routes.
@@ -410,7 +410,7 @@ Distance value is used in zebra daemon. Default RIP distance is 120.
 .. index:: distance (1-255)
 .. clicmd:: distance (1-255)
 
-.. index:: no distance (1-255)
+.. index:: distance (1-255)
 .. clicmd:: no distance (1-255)
 
    Set default RIP distance to specified value.
@@ -418,7 +418,7 @@ Distance value is used in zebra daemon. Default RIP distance is 120.
 .. index:: distance (1-255) A.B.C.D/M
 .. clicmd:: distance (1-255) A.B.C.D/M
 
-.. index:: no distance (1-255) A.B.C.D/M
+.. index:: distance (1-255) A.B.C.D/M
 .. clicmd:: no distance (1-255) A.B.C.D/M
 
    Set default RIP distance to specified value when the route's source IP
@@ -427,7 +427,7 @@ Distance value is used in zebra daemon. Default RIP distance is 120.
 .. index:: distance (1-255) A.B.C.D/M ACCESS-LIST
 .. clicmd:: distance (1-255) A.B.C.D/M ACCESS-LIST
 
-.. index:: no distance (1-255) A.B.C.D/M ACCESS-LIST
+.. index:: distance (1-255) A.B.C.D/M ACCESS-LIST
 .. clicmd:: no distance (1-255) A.B.C.D/M ACCESS-LIST
 
    Set default RIP distance to specified value when the route's source IP
@@ -539,7 +539,7 @@ To prevent such unauthenticated querying of routes disable RIPv1,
 .. index:: ip rip authentication mode md5
 .. clicmd:: ip rip authentication mode md5
 
-.. index:: no ip rip authentication mode md5
+.. index:: ip rip authentication mode md5
 .. clicmd:: no ip rip authentication mode md5
 
    Set the interface with RIPv2 MD5 authentication.
@@ -547,7 +547,7 @@ To prevent such unauthenticated querying of routes disable RIPv1,
 .. index:: ip rip authentication mode text
 .. clicmd:: ip rip authentication mode text
 
-.. index:: no ip rip authentication mode text
+.. index:: ip rip authentication mode text
 .. clicmd:: no ip rip authentication mode text
 
    Set the interface with RIPv2 simple password authentication.
@@ -555,7 +555,7 @@ To prevent such unauthenticated querying of routes disable RIPv1,
 .. index:: ip rip authentication string STRING
 .. clicmd:: ip rip authentication string STRING
 
-.. index:: no ip rip authentication string STRING
+.. index:: ip rip authentication string STRING
 .. clicmd:: no ip rip authentication string STRING
 
    RIP version 2 has simple text authentication. This command sets
@@ -564,7 +564,7 @@ To prevent such unauthenticated querying of routes disable RIPv1,
 .. index:: ip rip authentication key-chain KEY-CHAIN
 .. clicmd:: ip rip authentication key-chain KEY-CHAIN
 
-.. index:: no ip rip authentication key-chain KEY-CHAIN
+.. index:: ip rip authentication key-chain KEY-CHAIN
 .. clicmd:: no ip rip authentication key-chain KEY-CHAIN
 
    Specify Keyed MD5 chain.
@@ -610,7 +610,7 @@ RIP Timers
    The ``timers basic`` command allows the the default values of the timers
    listed above to be changed.
 
-.. index:: no timers basic
+.. index:: timers basic
 .. clicmd:: no timers basic
 
    The `no timers basic` command will reset the timers to the default settings
index 3d19306a757e629b46efe30475a59017ec575d18..fa8eee815deea1c138812cfd59ef2d99e8426bdf 100644 (file)
@@ -288,7 +288,7 @@ Route Map Set Command
 
    Subtract the BGP local preference from an existing `local_pref`.
 
-.. index:: [no] set distance DISTANCE
+.. index:: set distance DISTANCE
 .. clicmd:: [no] set distance DISTANCE
 
    Set the Administrative distance to DISTANCE to use for the route.
@@ -299,7 +299,7 @@ Route Map Set Command
 
    Set the route's weight.
 
-.. index:: [no] set metric <[+|-](1-4294967295)|rtt|+rtt|-rtt>
+.. index:: set metric <[+|-](1-4294967295)|rtt|+rtt|-rtt>
 .. clicmd:: [no] set metric <[+|-](1-4294967295)|rtt|+rtt|-rtt>
 
    Set the BGP attribute MED to a specific value. Use `+`/`-` to add or subtract
@@ -387,7 +387,7 @@ Route Map Optimization Command
    of all the prefixes in all the prefix-lists that are included in the
    match rule of all the sequences of a route-map.
 
-.. index:: no route-map optimization
+.. index:: route-map optimization
 .. clicmd:: no route-map optimization
 
    Disable the route-map processing optimization.
index f8ec98c964f8ebf1aba65ab64d9a2371e887ade0..451df1aa4e2243871cf85235421cc5b50f2f183d 100644 (file)
@@ -104,7 +104,7 @@ The following commands are independent of a specific cache server.
 .. index:: rpki polling_period (1-3600)
 .. clicmd:: rpki polling_period (1-3600)
 
-.. index:: no rpki polling_period
+.. index:: rpki polling_period
 .. clicmd:: no rpki polling_period
 
    Set the number of seconds the router waits until the router asks the cache
@@ -117,7 +117,7 @@ The following commands are independent of a specific cache server.
 .. index:: rpki cache (A.B.C.D|WORD) PORT [SSH_USERNAME] [SSH_PRIVKEY_PATH] [SSH_PUBKEY_PATH] [KNOWN_HOSTS_PATH] PREFERENCE
 .. clicmd:: rpki cache (A.B.C.D|WORD) PORT [SSH_USERNAME] [SSH_PRIVKEY_PATH] [SSH_PUBKEY_PATH] [KNOWN_HOSTS_PATH] PREFERENCE
 
-.. index:: no rpki cache (A.B.C.D|WORD) [PORT] PREFERENCE
+.. index:: rpki cache (A.B.C.D|WORD) [PORT] PREFERENCE
 .. clicmd:: no rpki cache (A.B.C.D|WORD) [PORT] PREFERENCE
 
    Add a cache server to the socket. By default, the connection between router
@@ -157,7 +157,7 @@ Validating BGP Updates
 .. index:: match rpki notfound|invalid|valid
 .. clicmd:: match rpki notfound|invalid|valid
 
-.. index:: no match rpki notfound|invalid|valid
+.. index:: match rpki notfound|invalid|valid
 .. clicmd:: no match rpki notfound|invalid|valid
 
     Create a clause for a route map to match prefixes with the specified RPKI
@@ -190,7 +190,7 @@ Debugging
 .. index:: debug rpki
 .. clicmd:: debug rpki
 
-.. index:: no debug rpki
+.. index:: debug rpki
 .. clicmd:: no debug rpki
 
    Enable or disable debugging output for RPKI.
@@ -271,5 +271,5 @@ RPKI Configuration Example
    route-map rpki permit 40
    !
 
-.. [Securing-BGP] Geoff Huston, Randy Bush: Securing BGP, In: The Internet Protocol Journal, Volume 14, No. 2, 2011. <http://www.cisco.com/web/about/ac123/ac147/archived_issues/ipj_14-2/142_bgp.html>
-.. [Resource-Certification] Geoff Huston: Resource Certification, In: The Internet Protocol Journal, Volume 12, No.1, 2009. <http://www.cisco.com/web/about/ac123/ac147/archived_issues/ipj_12-1/121_resource.html>
+.. [Securing-BGP] Geoff Huston, Randy Bush: Securing BGP, In: The Internet Protocol Journal, Volume 14, No. 2, 2011. <https://www.cisco.com/c/dam/en_us/about/ac123/ac147/archived_issues/ipj_14-2/ipj_14-2.pdf>
+.. [Resource-Certification] Geoff Huston: Resource Certification, In: The Internet Protocol Journal, Volume 12, No.1, 2009. <https://www.cisco.com/c/dam/en_us/about/ac123/ac147/archived_issues/ipj_12-1/ipj_12-1.pdf>
diff --git a/doc/user/scripting.rst b/doc/user/scripting.rst
new file mode 100644 (file)
index 0000000..b0295e5
--- /dev/null
@@ -0,0 +1,28 @@
+.. _scripting:
+
+*********
+Scripting
+*********
+
+The behavior of FRR may be extended or customized using its built-in scripting
+capabilities.
+
+Some configuration commands accept the name of a Lua script to call to perform
+some task or make some decision. These scripts have their environments
+populated with some set of inputs, and are expected to populate some set of
+output variables, which are read by FRR after the script completes. The names
+and expected contents of these scripts are documented alongside the commands
+that support them.
+
+These scripts live in :file:`/etc/frr/scripts/` by default. This is
+configurable at compile time via ``--with-scriptdir``. It may be
+overriden at runtime with the ``--scriptdir`` daemon option.
+
+In order to use scripting, FRR must be built with ``--enable-scripting``.
+
+.. note::
+
+   Scripts are typically loaded just-in-time. This means you can change the
+   contents of a script that is in use without restarting FRR. Not all
+   scripting locations may behave this way; refer to the documentation for the
+   particular location.
index 57ef141c7e8a9c89a6dd0434c0bdc45351fb5a4b..90eae4d65a29bf2213b0b5ab882a49a131b8ccfa 100644 (file)
@@ -33,7 +33,7 @@ All sharp commands are under the enable node and preceded by the ``sharp``
 keyword. At present, no sharp commands will be preserved in the config.
 
 .. index:: sharp install
-.. clicmd:: sharp install routes A.B.C.D <nexthop <E.F.G.H|X:X::X:X>|nexthop-group NAME> (1-1000000) [instance (0-255)] [repeat (2-1000)]
+.. clicmd:: sharp install routes A.B.C.D <nexthop <E.F.G.H|X:X::X:X>|nexthop-group NAME> (1-1000000) [instance (0-255)] [repeat (2-1000)] [opaque WORD]
 
    Install up to 1,000,000 (one million) /32 routes starting at ``A.B.C.D``
    with specified nexthop ``E.F.G.H`` or ``X:X::X:X``. The nexthop is
@@ -46,7 +46,8 @@ keyword. At present, no sharp commands will be preserved in the config.
    receives success notifications for all routes this is logged as well.
    Instance (0-255) if specified causes the routes to be installed in a different
    instance. If repeat is used then we will install/uninstall the routes the
-   number of times specified.
+   number of times specified.  If the keyword opaque is specified then the
+   next word is sent down to zebra as part of the route installation.
 
 .. index:: sharp remove
 .. clicmd:: sharp remove routes A.B.C.D (1-1000000)
index 0087d41a2345cc298a613eb4ab61d3c95e2c54af..ebbe178e0bea8d55335c480e305101f268cfd3c1 100644 (file)
@@ -11,7 +11,9 @@ a SNMP agent using the the AgentX protocol (:rfc:`2741`) and make the
 routing protocol MIBs available through it.
 
 Note that SNMP Support needs to be enabled at compile-time and loaded as module
-on daemon startup. Refer to :ref:`loadable-module-support` on the latter.
+on daemon startup. Refer to :ref:`loadable-module-support` on the latter.  If
+you do not start the daemons with snmp module support snmp will not work
+properly.
 
 .. _getting-and-installing-an-snmp-agent:
 
@@ -130,7 +132,7 @@ Here is the syntax for using AgentX:
 
 .. index:: agentx
 .. clicmd:: agentx
-.. index:: no agentx
+.. index:: agentx
 .. clicmd:: no agentx
 
 
index dd7a193e34acaecc0ccd87449882dad254324f22..3585245e852e2336216853d84ff6d6bfeb317b8d 100644 (file)
@@ -27,6 +27,7 @@ user_RSTFILES = \
        doc/user/ospf_fundamentals.rst \
        doc/user/overview.rst \
        doc/user/packet-dumps.rst \
+       doc/user/pathd.rst \
        doc/user/pim.rst \
        doc/user/ripd.rst \
        doc/user/pbr.rst \
@@ -34,6 +35,7 @@ user_RSTFILES = \
        doc/user/routemap.rst \
        doc/user/routeserver.rst \
        doc/user/rpki.rst \
+       doc/user/scripting.rst \
        doc/user/setup.rst \
        doc/user/sharp.rst \
        doc/user/snmp.rst \
index cb9c74ceea00374ada7a0cd8a5d0cde6edbc8edd..4f03e543acd0ed2f668300df31e65ea39984eff3 100644 (file)
@@ -149,7 +149,7 @@ Defaults section.
      exit-vnc
 
 
-.. index:: no vnc nve-group NAME
+.. index:: vnc nve-group NAME
 .. clicmd:: no vnc nve-group NAME
 
    Delete the NVE group named `name`.
@@ -322,7 +322,7 @@ L2 Group Configuration.
        exit-vnc
 
 
-.. index:: no vnc l2-group NAME
+.. index:: vnc l2-group NAME
 .. clicmd:: no vnc l2-group NAME
 
    Delete the L2 group named `name`.
@@ -338,7 +338,7 @@ The following statements are valid in a L2 group definition:
 .. index:: labels LABEL-LIST
 .. clicmd:: labels LABEL-LIST
 
-.. index:: no labels LABEL-LIST
+.. index:: labels LABEL-LIST
 .. clicmd:: no labels LABEL-LIST
 
    Add or remove labels associated with the group. `label-list` is a
@@ -490,7 +490,7 @@ Redistribution Command Syntax
 .. index:: vnc redistribute ipv4|ipv6 bgp-direct-to-nve-groups view VIEWNAME
 .. clicmd:: vnc redistribute ipv4|ipv6 bgp-direct-to-nve-groups view VIEWNAME
 
-.. index:: no vnc redistribute ipv4|ipv6 bgp|bgp-direct|bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static
+.. index:: vnc redistribute ipv4|ipv6 bgp|bgp-direct|bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static
 .. clicmd:: no vnc redistribute ipv4|ipv6 bgp|bgp-direct|bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static
 
    Import (or do not import) prefixes from another routing protocols. Specify
@@ -511,7 +511,7 @@ Redistribution Command Syntax
 .. index:: vnc redistribute nve-group GROUP-NAME
 .. clicmd:: vnc redistribute nve-group GROUP-NAME
 
-.. index:: no vnc redistribute nve-group GROUP-NAME
+.. index:: vnc redistribute nve-group GROUP-NAME
 .. clicmd:: no vnc redistribute nve-group GROUP-NAME
 
    When using `nve-group` mode, assign (or do not assign) the NVE group
index cb70da3f3b4d31d66002d390e61337939f0f11b5..a39bd53844559310c1ded644bb3202f41aa6463f 100644 (file)
@@ -358,21 +358,21 @@ using VRRPv2.
 
 All interface configuration commands are documented below.
 
-.. index:: [no] vrrp (1-255) [version (2-3)]
+.. index:: vrrp (1-255) [version (2-3)]
 .. clicmd:: [no] vrrp (1-255) [version (2-3)]
 
    Create a VRRP router with the specified VRID on the interface. Optionally
    specify the protocol version. If the protocol version is not specified, the
    default is VRRPv3.
 
-.. index:: [no] vrrp (1-255) advertisement-interval (10-40950)
+.. index:: vrrp (1-255) advertisement-interval (10-40950)
 .. clicmd:: [no] vrrp (1-255) advertisement-interval (10-40950)
 
    Set the advertisement interval. This is the interval at which VRRP
    advertisements will be sent. Values are given in milliseconds, but must be
    multiples of 10, as VRRP itself uses centiseconds.
 
-.. index:: [no] vrrp (1-255) ip A.B.C.D
+.. index:: vrrp (1-255) ip A.B.C.D
 .. clicmd:: [no] vrrp (1-255) ip A.B.C.D
 
    Add an IPv4 address to the router. This address must already be configured
@@ -380,7 +380,7 @@ All interface configuration commands are documented below.
    implicitly activate the router; see :clicmd:`[no] vrrp (1-255) shutdown` to
    override this behavior.
 
-.. index:: [no] vrrp (1-255) ipv6 X:X::X:X
+.. index:: vrrp (1-255) ipv6 X:X::X:X
 .. clicmd:: [no] vrrp (1-255) ipv6 X:X::X:X
 
    Add an IPv6 address to the router. This address must already be configured
@@ -391,14 +391,14 @@ All interface configuration commands are documented below.
    This command will fail if the protocol version is set to VRRPv2, as VRRPv2
    does not support IPv6.
 
-.. index:: [no] vrrp (1-255) preempt
+.. index:: vrrp (1-255) preempt
 .. clicmd:: [no] vrrp (1-255) preempt
 
    Toggle preempt mode. When enabled, preemption allows Backup routers with
    higher priority to take over Master status from the existing Master. Enabled
    by default.
 
-.. index:: [no] vrrp (1-255) priority (1-254)
+.. index:: vrrp (1-255) priority (1-254)
 .. clicmd:: [no] vrrp (1-255) priority (1-254)
 
    Set the router priority. The router with the highest priority is elected as
@@ -406,7 +406,7 @@ All interface configuration commands are documented below.
    the same priority, the router with the highest primary IP address is elected
    as the Master. Priority value 255 is reserved for the acting Master router.
 
-.. index:: [no] vrrp (1-255) shutdown
+.. index:: vrrp (1-255) shutdown
 .. clicmd:: [no] vrrp (1-255) shutdown
 
    Place the router into administrative shutdown. VRRP will not activate for
@@ -427,7 +427,7 @@ Show commands, global defaults and debugging configuration commands.
    VRID will only show routers with that VRID. Specifying ``json`` will dump
    each router state in a JSON array.
 
-.. index:: [no] debug vrrp [{protocol|autoconfigure|packets|sockets|ndisc|arp|zebra}]
+.. index:: debug vrrp [{protocol|autoconfigure|packets|sockets|ndisc|arp|zebra}]
 .. clicmd:: [no] debug vrrp [{protocol|autoconfigure|packets|sockets|ndisc|arp|zebra}]
 
    Toggle debugging logs for VRRP components.
@@ -457,7 +457,7 @@ Show commands, global defaults and debugging configuration commands.
    zebra
       Logs communications with Zebra.
 
-.. index:: [no] vrrp default <advertisement-interval (1-4096)|preempt|priority (1-254)|shutdown>
+.. index:: vrrp default <advertisement-interval (1-4096)|preempt|priority (1-254)|shutdown>
 .. clicmd:: [no] vrrp default <advertisement-interval (1-4096)|preempt|priority (1-254)|shutdown>
 
    Configure defaults for new VRRP routers. These values will not affect
@@ -480,7 +480,7 @@ After configuring the interfaces as described in
 :ref:`vrrp-system-configuration`, and configuring any defaults you may want,
 execute the following command:
 
-.. index:: [no] vrrp autoconfigure [version (2-3)]
+.. index:: vrrp autoconfigure [version (2-3)]
 .. clicmd:: [no] vrrp autoconfigure [version (2-3)]
 
    Generates VRRP configuration based on the interface configuration on the
index dd754a92ee115ac29689685a001e3e9d78d450f4..b1339f26e51b8c3e0c8c59f6203c2688865e2e08 100644 (file)
@@ -52,7 +52,7 @@ and the :clicmd:`terminal paginate` command:
    This variable should be set by the user according to their preferences,
    in their :file:`~/.profile` file.
 
-.. index:: [no] terminal paginate
+.. index:: terminal paginate
 .. clicmd:: [no] terminal paginate
 
    Enables/disables vtysh output pagination.  This command is intended to
@@ -165,7 +165,7 @@ in whose file the error is made.
 .. index:: service integrated-vtysh-config
 .. clicmd:: service integrated-vtysh-config
 
-.. index:: no service integrated-vtysh-config
+.. index:: service integrated-vtysh-config
 .. clicmd:: no service integrated-vtysh-config
 
    Control whether integrated :file:`frr.conf` file is written when
index df04a1e375e7f45bb1a859875759ebc17d07806e..b29e602fe5b3e324a7bbde2777470799771e0ba8 100644 (file)
@@ -22,7 +22,7 @@ WATCHFRR commands
    Give status information about the state of the different daemons being
    watched by WATCHFRR
 
-.. index:: [no] watchfrr ignore DAEMON
+.. index:: watchfrr ignore DAEMON
 .. clicmd:: [no] watchfrr ignore DAEMON
 
    Tell WATCHFRR to ignore a particular DAEMON if it goes unresponsive.
index 5c7f4ac7731cbc07e89b3af971f5be47f1ac43f9..b94c248b33165a76f0bef6a01be44693b2e9942f 100644 (file)
@@ -126,7 +126,7 @@ Standard Commands
 .. index:: shutdown
 
 .. clicmd:: shutdown
-.. index:: no shutdown
+.. index:: shutdown
 
 .. clicmd:: no shutdown
 
@@ -138,10 +138,10 @@ Standard Commands
 .. index:: ipv6 address ADDRESS/PREFIX
 
 .. clicmd:: ipv6 address ADDRESS/PREFIX
-.. index:: no ip address ADDRESS/PREFIX
+.. index:: ip address ADDRESS/PREFIX
 
 .. clicmd:: no ip address ADDRESS/PREFIX
-.. index:: no ipv6 address ADDRESS/PREFIX
+.. index:: ipv6 address ADDRESS/PREFIX
 
 .. clicmd:: no ipv6 address ADDRESS/PREFIX
 
@@ -150,7 +150,7 @@ Standard Commands
 .. index:: ip address LOCAL-ADDR peer PEER-ADDR/PREFIX
 
 .. clicmd:: ip address LOCAL-ADDR peer PEER-ADDR/PREFIX
-.. index:: no ip address LOCAL-ADDR peer PEER-ADDR/PREFIX
+.. index:: ip address LOCAL-ADDR peer PEER-ADDR/PREFIX
 
 .. clicmd:: no ip address LOCAL-ADDR peer PEER-ADDR/PREFIX
 
@@ -171,7 +171,7 @@ Standard Commands
 .. index:: multicast
 
 .. clicmd:: multicast
-.. index:: no multicast
+.. index:: multicast
 
 .. clicmd:: no multicast
 
@@ -180,7 +180,7 @@ Standard Commands
 .. index:: bandwidth (1-10000000)
 
 .. clicmd:: bandwidth (1-10000000)
-.. index:: no bandwidth (1-10000000)
+.. index:: bandwidth (1-10000000)
 
 .. clicmd:: no bandwidth (1-10000000)
 
@@ -191,7 +191,7 @@ Standard Commands
 .. index:: link-detect
 
 .. clicmd:: link-detect
-.. index:: no link-detect
+.. index:: link-detect
 
 .. clicmd:: no link-detect
 
@@ -215,7 +215,7 @@ Link Parameters Commands
 .. index:: link-params
 .. clicmd:: link-params
 
-.. index:: no link-param
+.. index:: link-param
 .. clicmd:: no link-param
 
    Enter into the link parameters sub node. At least 'enable' must be
@@ -361,6 +361,25 @@ is interpreted as the Administrative Distance and the low three bytes
 are read in as the metric.  This special case is to facilitate VRF
 default routes.
 
+Route Replace Semantics
+=======================
+
+When using the Linux Kernel as a forwarding plane, routes are installed
+with a metric of 20 to the kernel.  Please note that the kernel's metric
+value bears no resemblence to FRR's RIB metric or admin distance.  It
+merely is a way for the Linux Kernel to decide which route to use if it
+has multiple routes for the same prefix from multiple sources.  An example
+here would be if someone else was running another routing suite besides
+FRR at the same time, the kernel must choose what route to use to forward
+on.  FRR choose the value of 20 because of two reasons.  FRR wanted a
+value small enough to be choosen but large enough that the operator could
+allow route prioritization by the kernel when multiple routing suites are
+being run and FRR wanted to take advantage of Route Replace semantics that
+the linux kernel offers.  In order for Route Replacement semantics to
+work FRR must use the same metric when issuing the replace command.
+Currently FRR only supports Route Replace semantics using the Linux
+Kernel.
+
 Virtual Routing and Forwarding
 ==============================
 
@@ -510,7 +529,7 @@ The push action is generally used for LER devices, which want to encapsulate
 all traffic for a wished destination into an MPLS label. This action is stored
 in routing entry, and can be configured like a route:
 
-.. index:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL
+.. index:: ip route NETWORK MASK GATEWAY|INTERFACE label LABEL
 .. clicmd:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL
 
    NETWORK and MASK stand for the IP prefix entry to be added as static
@@ -541,7 +560,7 @@ The swap action is generally used for LSR devices, which swap a packet with a
 label, with an other label. The Pop action is used on LER devices, at the
 termination of the MPLS traffic; this is used to remove MPLS header.
 
-.. index:: [no] mpls lsp INCOMING_LABEL GATEWAY OUTGOING_LABEL|explicit-null|implicit-null
+.. index:: mpls lsp INCOMING_LABEL GATEWAY OUTGOING_LABEL|explicit-null|implicit-null
 .. clicmd:: [no] mpls lsp INCOMING_LABEL GATEWAY OUTGOING_LABEL|explicit-null|implicit-null
 
    INCOMING_LABEL and OUTGOING_LABEL are MPLS labels with values ranging from 16
@@ -592,7 +611,7 @@ unicast topology!
 .. index:: ip multicast rpf-lookup-mode MODE
 .. clicmd:: ip multicast rpf-lookup-mode MODE
 
-.. index:: no ip multicast rpf-lookup-mode [MODE]
+.. index:: ip multicast rpf-lookup-mode [MODE]
 .. clicmd:: no ip multicast rpf-lookup-mode [MODE]
 
    MODE sets the method used to perform RPF lookups. Supported modes:
@@ -655,7 +674,7 @@ unicast topology!
 .. index:: ip mroute PREFIX NEXTHOP [DISTANCE]
 .. clicmd:: ip mroute PREFIX NEXTHOP [DISTANCE]
 
-.. index:: no ip mroute PREFIX NEXTHOP [DISTANCE]
+.. index:: ip mroute PREFIX NEXTHOP [DISTANCE]
 .. clicmd:: no ip mroute PREFIX NEXTHOP [DISTANCE]
 
    Adds a static route entry to the Multicast RIB. This performs exactly as the
@@ -740,6 +759,12 @@ IPv6 example for OSPFv3.
    not created at startup.  On Debian, FRR might start before ifupdown
    completes. Consider a reboot test.
 
+.. index:: zebra route-map delay-timer (0-600)
+.. clicmd:: [no] zebra route-map delay-timer (0-600)
+
+   Set the delay before any route-maps are processed in zebra.  The
+   default time for this is 5 seconds.
+
 .. _zebra-fib-push-interface:
 
 zebra FIB push interface
@@ -816,7 +841,7 @@ FPM Commands
    ``127.0.0.1`` port ``2620``.
 
 
-.. index:: no fpm connection ip A.B.C.D port (1-65535)
+.. index:: fpm connection ip A.B.C.D port (1-65535)
 .. clicmd:: no fpm connection ip A.B.C.D port (1-65535)
 
   Configure ``zebra`` to connect to the default FPM server at ``127.0.0.1``
@@ -876,7 +901,7 @@ FPM Commands
    to connect to it immediately.
 
 
-.. index:: no fpm address [<A.B.C.D|X:X::X:X> [port (1-65535)]]
+.. index:: fpm address [<A.B.C.D|X:X::X:X> [port (1-65535)]]
 .. clicmd:: no fpm address [<A.B.C.D|X:X::X:X> [port (1-65535)]]
 
    Disables FPM entirely. ``zebra`` will close any current connections and
@@ -890,7 +915,7 @@ FPM Commands
    group repeated route next hop information.
 
 
-.. index:: no fpm use-next-hop-groups
+.. index:: fpm use-next-hop-groups
 .. clicmd:: no fpm use-next-hop-groups
 
    Use the old known FPM behavior of including next hop information in the
@@ -1064,13 +1089,13 @@ Many routing protocols require a router-id to be configured. To have a
 consistent router-id across all daemons, the following commands are available
 to configure and display the router-id:
 
-.. index:: [no] [ip] router-id A.B.C.D
+.. index:: router-id A.B.C.D
 .. clicmd:: [no] [ip] router-id A.B.C.D
 
    Allow entering of the router-id.  This command also works under the
    vrf subnode, to allow router-id's per vrf.
 
-.. index:: [no] [ip] router-id A.B.C.D vrf NAME
+.. index:: router-id A.B.C.D vrf NAME
 .. clicmd:: [no] [ip] router-id A.B.C.D vrf NAME
 
    Configure the router-id of this router from the configure NODE.
@@ -1085,7 +1110,7 @@ to configure and display the router-id:
 
 For protocols requiring an IPv6 router-id, the following commands are available:
 
-.. index:: [no] ipv6 router-id X:X::X:X
+.. index:: ipv6 router-id X:X::X:X
 .. clicmd:: [no] ipv6 router-id X:X::X:X
 
    Configure the IPv6 router-id of this router. Like its IPv4 counterpart,
index 3610b3a869803dae2a9c84ed44ab538a13738d2d..00d8ea8867284b2161c7bb618557e32fd2dff7ce 100644 (file)
@@ -29,6 +29,7 @@
 #include "eigrp_structs.h"
 #include "eigrpd.h"
 #include "eigrp_zebra.h"
+#include "eigrp_cli.h"
 
 #ifndef VTYSH_EXTRACT_PL
 #include "eigrpd/eigrp_cli_clippy.c"
diff --git a/eigrpd/eigrp_cli.h b/eigrpd/eigrp_cli.h
new file mode 100644 (file)
index 0000000..c5f2fd8
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * EIGRP CLI Functions.
+ * Copyright (C) 2019
+ * Authors:
+ *   Donnie Savage
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _EIGRP_CLI_H_
+#define _EIGRP_CLI_H_
+
+/*Prototypes*/
+extern void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode,
+                                 bool show_defaults);
+extern void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode);
+extern void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode,
+                                    bool show_defaults);
+extern void eigrp_cli_show_passive_interface(struct vty *vty,
+                                            struct lyd_node *dnode,
+                                            bool show_defaults);
+extern void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode,
+                                      bool show_defaults);
+extern void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode,
+                                   bool show_defaults);
+extern void eigrp_cli_show_maximum_paths(struct vty *vty,
+                                        struct lyd_node *dnode,
+                                        bool show_defaults);
+extern void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode,
+                                  bool show_defaults);
+extern void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode,
+                                  bool show_defaults);
+extern void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode,
+                                   bool show_defaults);
+extern void eigrp_cli_show_redistribute(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults);
+extern void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode,
+                                bool show_defaults);
+extern void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode,
+                                    bool show_defaults);
+extern void eigrp_cli_show_hello_interval(struct vty *vty,
+                                         struct lyd_node *dnode,
+                                         bool show_defaults);
+extern void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode,
+                                    bool show_defaults);
+extern void eigrp_cli_show_summarize_address(struct vty *vty,
+                                            struct lyd_node *dnode,
+                                            bool show_defaults);
+extern void eigrp_cli_show_authentication(struct vty *vty,
+                                         struct lyd_node *dnode,
+                                         bool show_defaults);
+extern void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode,
+                                   bool show_defaults);
+extern void eigrp_cli_init(void);
+
+#endif /*EIGRP_CLI_H_ */
index 3a103fb9f2e5d2559ba67c4cb0b13541fac02239..149cf00efca772c4a0187f44c56904128c98a5d9 100644 (file)
@@ -110,10 +110,8 @@ enum metric_change { METRIC_DECREASE, METRIC_SAME, METRIC_INCREASE };
 #define EIGRP_IFTYPE_NONE 0
 #define EIGRP_IFTYPE_POINTOPOINT 1
 #define EIGRP_IFTYPE_BROADCAST 2
-#define EIGRP_IFTYPE_NBMA 3
-#define EIGRP_IFTYPE_POINTOMULTIPOINT 4
-#define EIGRP_IFTYPE_LOOPBACK 5
-#define EIGRP_IFTYPE_MAX 6
+#define EIGRP_IFTYPE_LOOPBACK 3
+#define EIGRP_IFTYPE_MAX 4
 
 #define EIGRP_IF_ACTIVE                  0
 #define EIGRP_IF_PASSIVE                 1
@@ -124,10 +122,10 @@ enum metric_change { METRIC_DECREASE, METRIC_SAME, METRIC_INCREASE };
 #define EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL     2 // Remote external network
 
 /*EIGRP TT entry flags*/
-#define EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG     (1 << 0)
-#define EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG    (1 << 1)
-#define EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG       (1 << 2)
-#define EIGRP_NEXTHOP_ENTRY_EXTERNAL_FLAG      (1 << 3)
+#define EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG (1 << 0)
+#define EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG (1 << 1)
+#define EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG (1 << 2)
+#define EIGRP_ROUTE_DESCRIPTOR_EXTERNAL_FLAG (1 << 3)
 
 /*EIGRP FSM state count, event count*/
 #define EIGRP_FSM_STATE_MAX                  5
index dfce2acad4885ed7462f447222a42a2bc4a7cbc5..e1ad51a9dbb1f7d4350accd2788e75a4310e8601 100644 (file)
@@ -236,7 +236,8 @@ void show_ip_eigrp_topology_header(struct vty *vty, struct eigrp *eigrp)
                "Codes: P - Passive, A - Active, U - Update, Q - Query, R - Reply\n       r - reply Status, s - sia Status\n\n");
 }
 
-void show_ip_eigrp_prefix_entry(struct vty *vty, struct eigrp_prefix_entry *tn)
+void show_ip_eigrp_prefix_descriptor(struct vty *vty,
+                                    struct eigrp_prefix_descriptor *tn)
 {
        struct list *successors = eigrp_topology_get_successor(tn);
 
@@ -251,14 +252,15 @@ void show_ip_eigrp_prefix_entry(struct vty *vty, struct eigrp_prefix_entry *tn)
                list_delete(&successors);
 }
 
-void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp,
-                                struct eigrp_nexthop_entry *te, bool *first)
+void show_ip_eigrp_route_descriptor(struct vty *vty, struct eigrp *eigrp,
+                                   struct eigrp_route_descriptor *te,
+                                   bool *first)
 {
        if (te->reported_distance == EIGRP_MAX_METRIC)
                return;
 
        if (*first) {
-               show_ip_eigrp_prefix_entry(vty, te->prefix);
+               show_ip_eigrp_prefix_descriptor(vty, te->prefix);
                *first = false;
        }
 
index 348356bb3c74bff2fa7939acdbd97f581bbdfefc..0d512fc63fdd1b1fd7b9acfcb979adc8b7592f08 100644 (file)
@@ -151,11 +151,11 @@ extern void show_ip_eigrp_interface_sub(struct vty *, struct eigrp *,
                                        struct eigrp_interface *);
 extern void show_ip_eigrp_neighbor_sub(struct vty *, struct eigrp_neighbor *,
                                       int);
-extern void show_ip_eigrp_prefix_entry(struct vty *,
-                                      struct eigrp_prefix_entry *);
-extern void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp,
-                                       struct eigrp_nexthop_entry *ne,
-                                       bool *first);
+extern void show_ip_eigrp_prefix_descriptor(struct vty *vty,
+                                           struct eigrp_prefix_descriptor *tn);
+extern void show_ip_eigrp_route_descriptor(struct vty *vty, struct eigrp *eigrp,
+                                          struct eigrp_route_descriptor *ne,
+                                          bool *first);
 
 extern void eigrp_debug_init(void);
 
index a69a3eec0a214535e098f70cf209f0f5359182d4..d2d435bf2d5d8cba6e128fab48e21683bf1b8773 100644 (file)
@@ -77,6 +77,7 @@
 #include "linklist.h"
 #include "vty.h"
 
+#include "eigrpd/eigrp_types.h"
 #include "eigrpd/eigrp_structs.h"
 #include "eigrpd/eigrpd.h"
 #include "eigrpd/eigrp_interface.h"
@@ -88,6 +89,7 @@
 #include "eigrpd/eigrp_dump.h"
 #include "eigrpd/eigrp_topology.h"
 #include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_metric.h"
 
 /*
  * Prototypes
@@ -262,13 +264,13 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
 {
        // Loading base information from message
        // struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
-       struct eigrp_nexthop_entry *entry = msg->entry;
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
+       struct eigrp_route_descriptor *entry = msg->entry;
        uint8_t actual_state = prefix->state;
        enum metric_change change;
 
        if (entry == NULL) {
-               entry = eigrp_nexthop_entry_new();
+               entry = eigrp_route_descriptor_new();
                entry->adv_router = msg->adv_router;
                entry->ei = msg->adv_router->ei;
                entry->prefix = prefix;
@@ -286,7 +288,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
 
        switch (actual_state) {
        case EIGRP_FSM_STATE_PASSIVE: {
-               struct eigrp_nexthop_entry *head =
+               struct eigrp_route_descriptor *head =
                        listnode_head(prefix->entries);
 
                if (head->reported_distance < prefix->fdistance) {
@@ -307,7 +309,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
        }
        case EIGRP_FSM_STATE_ACTIVE_0: {
                if (msg->packet_type == EIGRP_OPC_REPLY) {
-                       struct eigrp_nexthop_entry *head =
+                       struct eigrp_route_descriptor *head =
                                listnode_head(prefix->entries);
 
                        listnode_delete(prefix->rij, entry->adv_router);
@@ -322,7 +324,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
                        return EIGRP_FSM_EVENT_LR_FCN;
                } else if (msg->packet_type == EIGRP_OPC_QUERY
                           && (entry->flags
-                              & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+                              & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
                        return EIGRP_FSM_EVENT_QACT;
                }
 
@@ -332,14 +334,14 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
        }
        case EIGRP_FSM_STATE_ACTIVE_1: {
                if (msg->packet_type == EIGRP_OPC_QUERY
-                   && (entry->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+                   && (entry->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
                        return EIGRP_FSM_EVENT_QACT;
                } else if (msg->packet_type == EIGRP_OPC_REPLY) {
                        listnode_delete(prefix->rij, entry->adv_router);
 
                        if (change == METRIC_INCREASE
                            && (entry->flags
-                               & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+                               & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
                                return EIGRP_FSM_EVENT_DINC;
                        } else if (prefix->rij->count) {
                                return EIGRP_FSM_KEEP_STATE;
@@ -350,7 +352,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
                } else if (msg->packet_type == EIGRP_OPC_UPDATE
                           && change == METRIC_INCREASE
                           && (entry->flags
-                              & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+                              & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
                        return EIGRP_FSM_EVENT_DINC;
                }
                return EIGRP_FSM_KEEP_STATE;
@@ -359,7 +361,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
        }
        case EIGRP_FSM_STATE_ACTIVE_2: {
                if (msg->packet_type == EIGRP_OPC_REPLY) {
-                       struct eigrp_nexthop_entry *head =
+                       struct eigrp_route_descriptor *head =
                                listnode_head(prefix->entries);
 
                        listnode_delete(prefix->rij, entry->adv_router);
@@ -385,7 +387,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
 
                        if (change == METRIC_INCREASE
                            && (entry->flags
-                               & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+                               & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
                                return EIGRP_FSM_EVENT_DINC;
                        } else if (prefix->rij->count) {
                                return EIGRP_FSM_KEEP_STATE;
@@ -396,7 +398,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
                } else if (msg->packet_type == EIGRP_OPC_UPDATE
                           && change == METRIC_INCREASE
                           && (entry->flags
-                              & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+                              & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
                        return EIGRP_FSM_EVENT_DINC;
                }
                return EIGRP_FSM_KEEP_STATE;
@@ -434,9 +436,9 @@ int eigrp_fsm_event(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg)
 {
        struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
        struct list *successors = eigrp_topology_get_successor(prefix);
-       struct eigrp_nexthop_entry *ne;
+       struct eigrp_route_descriptor *ne;
 
        assert(successors); // If this is NULL we have shit the bed, fun huh?
 
@@ -461,9 +463,9 @@ int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
 {
        struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
        struct list *successors = eigrp_topology_get_successor(prefix);
-       struct eigrp_nexthop_entry *ne;
+       struct eigrp_route_descriptor *ne;
 
        assert(successors); // If this is NULL somebody poked us in the eye.
 
@@ -487,8 +489,8 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
 {
        struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
-       struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
+       struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
 
        if (prefix->state == EIGRP_FSM_STATE_PASSIVE) {
                if (!eigrp_metrics_is_same(prefix->reported_metric,
@@ -515,8 +517,8 @@ int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg)
 {
        struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
-       struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
+       struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
 
        prefix->fdistance = prefix->distance = prefix->rdistance = ne->distance;
        prefix->reported_metric = ne->total_metric;
@@ -545,7 +547,7 @@ int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg)
 {
        struct list *successors = eigrp_topology_get_successor(msg->prefix);
-       struct eigrp_nexthop_entry *ne;
+       struct eigrp_route_descriptor *ne;
 
        assert(successors); // Trump and his big hands
 
@@ -566,8 +568,8 @@ int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg)
 {
        struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
-       struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
+       struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
 
        prefix->state = EIGRP_FSM_STATE_PASSIVE;
        prefix->distance = prefix->rdistance = ne->distance;
@@ -598,8 +600,8 @@ int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg)
 {
        struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
-       struct eigrp_nexthop_entry *best_successor;
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
+       struct eigrp_route_descriptor *best_successor;
        struct list *successors = eigrp_topology_get_successor(prefix);
 
        assert(successors); // Routing without a stack
@@ -628,7 +630,7 @@ int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg)
 {
        struct list *successors = eigrp_topology_get_successor(msg->prefix);
-       struct eigrp_nexthop_entry *ne;
+       struct eigrp_route_descriptor *ne;
 
        assert(successors); // Cats and no Dogs
 
index f512833e0a3ab467cfc9792ac01de42d9235eb96..13a2c4206fbe73f8004970ecea772aed22f32fb3 100644 (file)
@@ -745,12 +745,6 @@ void eigrp_hello_send(struct eigrp_interface *ei, uint8_t flags,
 {
        struct eigrp_packet *ep = NULL;
 
-       /* If this is passive interface, do not send EIGRP Hello.
-          if ((EIGRP_IF_PASSIVE_STATUS (ei) == EIGRP_IF_PASSIVE) ||
-          (ei->type != EIGRP_IFTYPE_NBMA))
-          return;
-       */
-
        if (IS_DEBUG_EIGRP_PACKET(0, SEND))
                zlog_debug("Queueing [Hello] Interface(%s)", IF_NAME(ei));
 
index dd43dd047857612d88b2f5e5b749557309dcfa46..74eff958da6b7591d822bd1e143095bf227a1f5d 100644 (file)
@@ -55,6 +55,8 @@
 #include "eigrpd/eigrp_memory.h"
 #include "eigrpd/eigrp_fsm.h"
 #include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_types.h"
+#include "eigrpd/eigrp_metric.h"
 
 struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp,
                                     struct prefix *p)
@@ -229,8 +231,8 @@ void eigrp_del_if_params(struct eigrp_if_params *eip)
 
 int eigrp_if_up(struct eigrp_interface *ei)
 {
-       struct eigrp_prefix_entry *pe;
-       struct eigrp_nexthop_entry *ne;
+       struct eigrp_prefix_descriptor *pe;
+       struct eigrp_route_descriptor *ne;
        struct eigrp_metrics metric;
        struct eigrp_interface *ei2;
        struct listnode *node, *nnode;
@@ -263,14 +265,14 @@ int eigrp_if_up(struct eigrp_interface *ei)
 
        /*Add connected entry to topology table*/
 
-       ne = eigrp_nexthop_entry_new();
+       ne = eigrp_route_descriptor_new();
        ne->ei = ei;
        ne->reported_metric = metric;
        ne->total_metric = metric;
        ne->distance = eigrp_calculate_metrics(eigrp, metric);
        ne->reported_distance = 0;
        ne->adv_router = eigrp->neighbor_self;
-       ne->flags = EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+       ne->flags = EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
 
        struct prefix dest_addr;
 
@@ -280,7 +282,7 @@ int eigrp_if_up(struct eigrp_interface *ei)
                                              &dest_addr);
 
        if (pe == NULL) {
-               pe = eigrp_prefix_entry_new();
+               pe = eigrp_prefix_descriptor_new();
                pe->serno = eigrp->serno;
                pe->destination = (struct prefix *)prefix_ipv4_new();
                prefix_copy(pe->destination, &dest_addr);
@@ -292,10 +294,10 @@ int eigrp_if_up(struct eigrp_interface *ei)
                pe->state = EIGRP_FSM_STATE_PASSIVE;
                pe->fdistance = eigrp_calculate_metrics(eigrp, metric);
                pe->req_action |= EIGRP_FSM_NEED_UPDATE;
-               eigrp_prefix_entry_add(eigrp->topology_table, pe);
+               eigrp_prefix_descriptor_add(eigrp->topology_table, pe);
                listnode_add(eigrp->topology_changes_internalIPV4, pe);
 
-               eigrp_nexthop_entry_add(eigrp, pe, ne);
+               eigrp_route_descriptor_add(eigrp, pe, ne);
 
                for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei2)) {
                        eigrp_update_send(ei2);
@@ -307,7 +309,7 @@ int eigrp_if_up(struct eigrp_interface *ei)
                struct eigrp_fsm_action_message msg;
 
                ne->prefix = pe;
-               eigrp_nexthop_entry_add(eigrp, pe, ne);
+               eigrp_route_descriptor_add(eigrp, pe, ne);
 
                msg.packet_type = EIGRP_OPC_UPDATE;
                msg.eigrp = eigrp;
@@ -416,7 +418,7 @@ uint8_t eigrp_default_iftype(struct interface *ifp)
 void eigrp_if_free(struct eigrp_interface *ei, int source)
 {
        struct prefix dest_addr;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
        struct eigrp *eigrp = ei->eigrp;
 
        if (source == INTERFACE_DOWN_BY_VTY) {
@@ -429,7 +431,8 @@ void eigrp_if_free(struct eigrp_interface *ei, int source)
        pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table,
                                              &dest_addr);
        if (pe)
-               eigrp_prefix_entry_delete(eigrp, eigrp->topology_table, pe);
+               eigrp_prefix_descriptor_delete(eigrp, eigrp->topology_table,
+                                              pe);
 
        eigrp_if_down(ei);
 
@@ -494,33 +497,3 @@ struct eigrp_interface *eigrp_if_lookup_by_name(struct eigrp *eigrp,
 
        return NULL;
 }
-
-uint32_t eigrp_bandwidth_to_scaled(uint32_t bandwidth)
-{
-       uint64_t temp_bandwidth = (256ull * 10000000) / bandwidth;
-
-       temp_bandwidth = temp_bandwidth < EIGRP_MAX_METRIC ? temp_bandwidth
-                                                          : EIGRP_MAX_METRIC;
-
-       return (uint32_t)temp_bandwidth;
-}
-
-uint32_t eigrp_scaled_to_bandwidth(uint32_t scaled)
-{
-       uint64_t temp_scaled = scaled * (256ull * 10000000);
-
-       temp_scaled =
-               temp_scaled < EIGRP_MAX_METRIC ? temp_scaled : EIGRP_MAX_METRIC;
-
-       return (uint32_t)temp_scaled;
-}
-
-uint32_t eigrp_delay_to_scaled(uint32_t delay)
-{
-       return delay * 256;
-}
-
-uint32_t eigrp_scaled_to_delay(uint32_t scaled)
-{
-       return scaled / 256;
-}
index 1e66dafde254595c54f7e1e6b1409b31882a7a85..68ab5125e3e587d18b7808c7331ca2cfb1efb522 100644 (file)
@@ -58,9 +58,4 @@ extern struct eigrp_interface *eigrp_if_lookup_by_name(struct eigrp *,
 /* Simulate down/up on the interface. */
 extern void eigrp_if_reset(struct interface *);
 
-extern uint32_t eigrp_bandwidth_to_scaled(uint32_t);
-extern uint32_t eigrp_scaled_to_bandwidth(uint32_t);
-extern uint32_t eigrp_delay_to_scaled(uint32_t);
-extern uint32_t eigrp_scaled_to_delay(uint32_t);
-
 #endif /* ZEBRA_EIGRP_INTERFACE_H_ */
index 6c44ce361c7e51bae2805cefabf3ddcea83a5890..b1a6498cbcb189dc43ddf8e7b47e250e07b3d188 100644 (file)
@@ -66,6 +66,8 @@
 #include "eigrpd/eigrp_filter.h"
 #include "eigrpd/eigrp_errors.h"
 #include "eigrpd/eigrp_vrf.h"
+#include "eigrpd/eigrp_cli.h"
+#include "eigrpd/eigrp_yang.h"
 //#include "eigrpd/eigrp_routemap.h"
 
 /* eigprd privileges */
index 85b14c28cec402b7a4c465f07362dfa1b5985940..57ca785340d63cc5108c9fd4a9e1d867fc0dec87 100644 (file)
@@ -37,6 +37,6 @@ DEFINE_MTYPE(EIGRPD, EIGRP_IPV4_INT_TLV, "EIGRP IPv4 TLV")
 DEFINE_MTYPE(EIGRPD, EIGRP_SEQ_TLV, "EIGRP SEQ TLV")
 DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_TLV, "EIGRP AUTH TLV")
 DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_SHA256_TLV, "EIGRP SHA TLV")
-DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_ENTRY, "EIGRP Prefix")
-DEFINE_MTYPE(EIGRPD, EIGRP_NEXTHOP_ENTRY, "EIGRP Nexthop Entry")
+DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_DESCRIPTOR, "EIGRP Prefix")
+DEFINE_MTYPE(EIGRPD, EIGRP_ROUTE_DESCRIPTOR, "EIGRP Nexthop Entry")
 DEFINE_MTYPE(EIGRPD, EIGRP_FSM_MSG, "EIGRP FSM Message")
index e4d02c09d490926d7e16420e54ca6764c97aa51c..21ecba2aaed00c8f8c23d75db91635fe34973ca8 100644 (file)
@@ -36,8 +36,8 @@ DECLARE_MTYPE(EIGRP_IPV4_INT_TLV)
 DECLARE_MTYPE(EIGRP_SEQ_TLV)
 DECLARE_MTYPE(EIGRP_AUTH_TLV)
 DECLARE_MTYPE(EIGRP_AUTH_SHA256_TLV)
-DECLARE_MTYPE(EIGRP_PREFIX_ENTRY)
-DECLARE_MTYPE(EIGRP_NEXTHOP_ENTRY)
+DECLARE_MTYPE(EIGRP_PREFIX_DESCRIPTOR)
+DECLARE_MTYPE(EIGRP_ROUTE_DESCRIPTOR)
 DECLARE_MTYPE(EIGRP_FSM_MSG)
 
 #endif /* _FRR_EIGRP_MEMORY_H */
diff --git a/eigrpd/eigrp_metric.c b/eigrpd/eigrp_metric.c
new file mode 100644 (file)
index 0000000..2b05db7
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * EIGRP Metric Math Functions.
+ * Copyright (C) 2013-2016
+ * Authors:
+ *   Donnie Savage
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_types.h"
+#include "eigrpd/eigrp_metric.h"
+
+eigrp_scaled_t eigrp_bandwidth_to_scaled(eigrp_bandwidth_t bandwidth)
+{
+       eigrp_bandwidth_t scaled = EIGRP_BANDWIDTH_MAX;
+
+       if (bandwidth != EIGRP_BANDWIDTH_MAX) {
+               scaled = (EIGRP_CLASSIC_SCALER * EIGRP_BANDWIDTH_SCALER);
+               scaled = scaled / bandwidth;
+
+               scaled = scaled ? scaled : EIGRP_BANDWIDTH_MIN;
+       }
+
+       scaled = (scaled < EIGRP_METRIC_MAX) ? scaled : EIGRP_METRIC_MAX;
+       return (eigrp_scaled_t)scaled;
+}
+
+eigrp_bandwidth_t eigrp_scaled_to_bandwidth(eigrp_scaled_t scaled)
+{
+       eigrp_bandwidth_t bandwidth = EIGRP_BANDWIDTH_MAX;
+
+       if (scaled != EIGRP_CLASSIC_MAX) {
+               bandwidth = (EIGRP_CLASSIC_SCALER * EIGRP_BANDWIDTH_SCALER);
+               bandwidth = scaled * bandwidth;
+               bandwidth = (bandwidth < EIGRP_METRIC_MAX)
+                                   ? bandwidth
+                                   : EIGRP_BANDWIDTH_MAX;
+       }
+
+       return bandwidth;
+}
+
+eigrp_scaled_t eigrp_delay_to_scaled(eigrp_delay_t delay)
+{
+       delay = delay ? delay : EIGRP_DELAY_MIN;
+       return delay * EIGRP_CLASSIC_SCALER;
+}
+
+eigrp_delay_t eigrp_scaled_to_delay(eigrp_scaled_t scaled)
+{
+       scaled = scaled / EIGRP_CLASSIC_SCALER;
+       scaled = scaled ? scaled : EIGRP_DELAY_MIN;
+
+       return scaled;
+}
+
+eigrp_metric_t eigrp_calculate_metrics(struct eigrp *eigrp,
+                                      struct eigrp_metrics metric)
+{
+       eigrp_metric_t composite = 0;
+
+       if (metric.delay == EIGRP_MAX_METRIC)
+               return EIGRP_METRIC_MAX;
+
+       /*
+        * EIGRP Composite =
+        * {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)}
+        */
+
+       if (eigrp->k_values[0])
+               composite += (eigrp->k_values[0] * metric.bandwidth);
+       if (eigrp->k_values[1])
+               composite += ((eigrp->k_values[1] * metric.bandwidth)
+                             / (256 - metric.load));
+       if (eigrp->k_values[2])
+               composite += (eigrp->k_values[2] * metric.delay);
+       if (eigrp->k_values[3] && !eigrp->k_values[4])
+               composite *= eigrp->k_values[3];
+       if (!eigrp->k_values[3] && eigrp->k_values[4])
+               composite *= (eigrp->k_values[4] / metric.reliability);
+       if (eigrp->k_values[3] && eigrp->k_values[4])
+               composite *= ((eigrp->k_values[4] / metric.reliability)
+                             + eigrp->k_values[3]);
+
+       composite =
+               (composite <= EIGRP_METRIC_MAX) ? composite : EIGRP_METRIC_MAX;
+
+       return composite;
+}
+
+eigrp_metric_t
+eigrp_calculate_total_metrics(struct eigrp *eigrp,
+                             struct eigrp_route_descriptor *entry)
+{
+       struct eigrp_interface *ei = entry->ei;
+       eigrp_delay_t temp_delay;
+       eigrp_bandwidth_t bw;
+
+       entry->total_metric = entry->reported_metric;
+       temp_delay = entry->total_metric.delay
+                    + eigrp_delay_to_scaled(ei->params.delay);
+
+       entry->total_metric.delay = temp_delay > EIGRP_METRIC_MAX_CLASSIC
+                                           ? EIGRP_METRIC_MAX_CLASSIC
+                                           : temp_delay;
+
+       bw = eigrp_bandwidth_to_scaled(ei->params.bandwidth);
+       entry->total_metric.bandwidth = entry->total_metric.bandwidth > bw
+                                               ? bw
+                                               : entry->total_metric.bandwidth;
+
+       return eigrp_calculate_metrics(eigrp, entry->total_metric);
+}
+
+bool eigrp_metrics_is_same(struct eigrp_metrics metric1,
+                          struct eigrp_metrics metric2)
+{
+       if ((metric1.bandwidth == metric2.bandwidth)
+           && (metric1.delay == metric2.delay)
+           && (metric1.hop_count == metric2.hop_count)
+           && (metric1.load == metric2.load)
+           && (metric1.reliability == metric2.reliability)
+           && (metric1.mtu[0] == metric2.mtu[0])
+           && (metric1.mtu[1] == metric2.mtu[1])
+           && (metric1.mtu[2] == metric2.mtu[2])) {
+               return true;
+       }
+
+       return false; /* if different */
+}
diff --git a/eigrpd/eigrp_metric.h b/eigrpd/eigrp_metric.h
new file mode 100644 (file)
index 0000000..8e9cd66
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * EIGRP Metric Math Functions.
+ * Copyright (C) 2013-2016
+ * Authors:
+ *   Donnie Savage
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _ZEBRA_EIGRP_METRIC_H_
+#define _ZEBRA_EIGRP_METRIC_H_
+
+/* Constants */
+#define EIGRP_BANDWIDTH_MIN 0x1ull               /* 1 */
+#define EIGRP_BANDWIDTH_SCALER 10000000ull       /* Inversion value */
+#define EIGRP_BANDWIDTH_MAX 0xffffffffffffffffull /* 1.84467441x10^19 */
+
+#define EIGRP_DELAY_MIN 0x1ull /* 1 */
+#define EIGRP_DELAY_PICO 1000000ull
+#define EIGRP_DELAY_MAX 0xffffffffffffffffull /* 1.84467441x10^19 */
+
+#define EIGRP_MAX_LOAD 256
+#define EIGRP_MAX_HOPS 100
+
+#define EIGRP_INACCESSIBLE 0xFFFFFFFFFFFFFFFFull
+
+#define EIGRP_METRIC_MAX 0xffffffffffffffffull /* 1.84467441x10^19 */
+#define EIGRP_METRIC_MAX_CLASSIC 0xffffffff
+#define EIGRP_METRIC_SCALER 65536             /* CLASSIC to WIDE conversion */
+
+#define EIGRP_CLASSIC_MAX 0xffffffff /* 4294967295 */
+#define EIGRP_CLASSIC_SCALER 256     /* IGRP to EIGRP conversion */
+
+
+/* Prototypes */
+extern eigrp_scaled_t eigrp_bandwidth_to_scaled(eigrp_bandwidth_t bw);
+extern eigrp_bandwidth_t eigrp_scaled_to_bandwidth(eigrp_scaled_t scale);
+extern eigrp_scaled_t eigrp_delay_to_scaled(eigrp_delay_t delay);
+extern eigrp_delay_t eigrp_scaled_to_delay(eigrp_scaled_t scale);
+
+extern eigrp_metric_t eigrp_calculate_metrics(struct eigrp *eigrp,
+                                             struct eigrp_metrics metric);
+extern eigrp_metric_t
+eigrp_calculate_total_metrics(struct eigrp *eigrp,
+                             struct eigrp_route_descriptor *rd);
+extern bool eigrp_metrics_is_same(struct eigrp_metrics m1,
+                                 struct eigrp_metrics m2);
+
+#endif /* _ZEBRA_EIGRP_METRIC_H_ */
index 2d5bb0a7d13e9969ff089abf2f0ead200086931e..1da2f7a10826df43036ec544552d852ce1591ee2 100644 (file)
@@ -343,7 +343,7 @@ void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty)
        eigrp_nbr_delete(nbr);
 }
 
-int eigrp_nbr_split_horizon_check(struct eigrp_nexthop_entry *ne,
+int eigrp_nbr_split_horizon_check(struct eigrp_route_descriptor *ne,
                                  struct eigrp_interface *ei)
 {
        if (ne->distance == EIGRP_MAX_METRIC)
index 1c308fa981d69de5f53471b371063f827ec7dd12..80ab1eded51af5d88e1e3576250527252b45ae8e 100644 (file)
@@ -54,6 +54,6 @@ extern struct eigrp_neighbor *
 eigrp_nbr_lookup_by_addr_process(struct eigrp *eigrp, struct in_addr addr);
 extern void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty);
 
-extern int eigrp_nbr_split_horizon_check(struct eigrp_nexthop_entry *ne,
+extern int eigrp_nbr_split_horizon_check(struct eigrp_route_descriptor *ne,
                                         struct eigrp_interface *ei);
 #endif /* _ZEBRA_EIGRP_NEIGHBOR_H */
index bd8ec2f879251fefd064806682a0e141b93ea68a..69dcc2025394af0efbf54910b2c2f053fe389b63 100644 (file)
@@ -292,7 +292,7 @@ void eigrp_if_update(struct interface *ifp)
                        continue;
 
                /* EIGRP must be on and Router-ID must be configured. */
-               if (eigrp->router_id.s_addr == 0)
+               if (eigrp->router_id.s_addr == INADDR_ANY)
                        continue;
 
                /* Run each network for this interface. */
@@ -346,76 +346,6 @@ int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p)
        return 1;
 }
 
-uint32_t eigrp_calculate_metrics(struct eigrp *eigrp,
-                                struct eigrp_metrics metric)
-{
-       uint64_t temp_metric;
-       temp_metric = 0;
-
-       if (metric.delay == EIGRP_MAX_METRIC)
-               return EIGRP_MAX_METRIC;
-
-       // EIGRP Metric =
-       // {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)}
-
-       if (eigrp->k_values[0])
-               temp_metric += (eigrp->k_values[0] * metric.bandwidth);
-       if (eigrp->k_values[1])
-               temp_metric += ((eigrp->k_values[1] * metric.bandwidth)
-                               / (256 - metric.load));
-       if (eigrp->k_values[2])
-               temp_metric += (eigrp->k_values[2] * metric.delay);
-       if (eigrp->k_values[3] && !eigrp->k_values[4])
-               temp_metric *= eigrp->k_values[3];
-       if (!eigrp->k_values[3] && eigrp->k_values[4])
-               temp_metric *= (eigrp->k_values[4] / metric.reliability);
-       if (eigrp->k_values[3] && eigrp->k_values[4])
-               temp_metric *= ((eigrp->k_values[4] / metric.reliability)
-                               + eigrp->k_values[3]);
-
-       if (temp_metric <= EIGRP_MAX_METRIC)
-               return (uint32_t)temp_metric;
-       else
-               return EIGRP_MAX_METRIC;
-}
-
-uint32_t eigrp_calculate_total_metrics(struct eigrp *eigrp,
-                                      struct eigrp_nexthop_entry *entry)
-{
-       struct eigrp_interface *ei = entry->ei;
-
-       entry->total_metric = entry->reported_metric;
-       uint64_t temp_delay =
-               (uint64_t)entry->total_metric.delay
-               + (uint64_t)eigrp_delay_to_scaled(ei->params.delay);
-       entry->total_metric.delay = temp_delay > EIGRP_MAX_METRIC
-                                           ? EIGRP_MAX_METRIC
-                                           : (uint32_t)temp_delay;
-
-       uint32_t bw = eigrp_bandwidth_to_scaled(ei->params.bandwidth);
-       entry->total_metric.bandwidth = entry->total_metric.bandwidth > bw
-                                               ? bw
-                                               : entry->total_metric.bandwidth;
-
-       return eigrp_calculate_metrics(eigrp, entry->total_metric);
-}
-
-uint8_t eigrp_metrics_is_same(struct eigrp_metrics metric1,
-                             struct eigrp_metrics metric2)
-{
-       if ((metric1.bandwidth == metric2.bandwidth)
-           && (metric1.delay == metric2.delay)
-           && (metric1.hop_count == metric2.hop_count)
-           && (metric1.load == metric2.load)
-           && (metric1.reliability == metric2.reliability)
-           && (metric1.mtu[0] == metric2.mtu[0])
-           && (metric1.mtu[1] == metric2.mtu[1])
-           && (metric1.mtu[2] == metric2.mtu[2]))
-               return 1;
-
-       return 0; // if different
-}
-
 void eigrp_external_routes_refresh(struct eigrp *eigrp, int type)
 {
 }
index 7839fc946b5e6fd398ed34e0d747c2142986a4db..eeb32ba3564145536c936f987b2d4e773aef5a2b 100644 (file)
@@ -43,11 +43,6 @@ extern int eigrp_if_drop_allspfrouters(struct eigrp *top, struct prefix *p,
                                       unsigned int ifindex);
 extern void eigrp_adjust_sndbuflen(struct eigrp *, unsigned int);
 
-extern uint32_t eigrp_calculate_metrics(struct eigrp *, struct eigrp_metrics);
-extern uint32_t eigrp_calculate_total_metrics(struct eigrp *,
-                                             struct eigrp_nexthop_entry *);
-extern uint8_t eigrp_metrics_is_same(struct eigrp_metrics,
-                                    struct eigrp_metrics);
 extern void eigrp_external_routes_refresh(struct eigrp *, int);
 
 #endif /* EIGRP_NETWORK_H_ */
index 5b87f7264016c37d382c4a6cb328a12d4f69e5c1..482667f633c214effffed11e30b9b4cc6d382e40 100644 (file)
@@ -34,6 +34,7 @@
 #include "eigrp_interface.h"
 #include "eigrp_network.h"
 #include "eigrp_zebra.h"
+#include "eigrp_cli.h"
 
 /* Helper functions. */
 static void redistribute_get_metrics(const struct lyd_node *dnode,
index f5f6ab5dffe55bdcfc394e0513b4bb7340bdda0a..252cd647a2b5804d8ba7d3e2af7d7a1d4019593d 100644 (file)
@@ -1144,7 +1144,7 @@ struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *s)
 }
 
 uint16_t eigrp_add_internalTLV_to_stream(struct stream *s,
-                                        struct eigrp_prefix_entry *pe)
+                                        struct eigrp_prefix_descriptor *pe)
 {
        uint16_t length;
 
index f354615fdb5f94cdd9ad91ab80307b6a575b4fe3..cb69bc26b294f5d0080afa311bfc6b261a1b100d 100644 (file)
 extern int eigrp_read(struct thread *);
 extern int eigrp_write(struct thread *);
 
-extern struct eigrp_packet *eigrp_packet_new(size_t, struct eigrp_neighbor *);
-extern struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *,
-                                                  struct eigrp_neighbor *);
-extern void eigrp_packet_free(struct eigrp_packet *);
-extern void eigrp_packet_delete(struct eigrp_interface *);
-extern void eigrp_packet_header_init(int, struct eigrp *, struct stream *,
-                                    uint32_t, uint32_t, uint32_t);
-extern void eigrp_packet_checksum(struct eigrp_interface *, struct stream *,
-                                 uint16_t);
+extern struct eigrp_packet *eigrp_packet_new(size_t size,
+                                            struct eigrp_neighbor *nbr);
+extern struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *old,
+                                                  struct eigrp_neighbor *nbr);
+extern void eigrp_packet_free(struct eigrp_packet *ep);
+extern void eigrp_packet_delete(struct eigrp_interface *ei);
+extern void eigrp_packet_header_init(int type, struct eigrp *eigrp,
+                                    struct stream *s, uint32_t flags,
+                                    uint32_t sequence, uint32_t ack);
+extern void eigrp_packet_checksum(struct eigrp_interface *ei, struct stream *s,
+                                 uint16_t length);
 
 extern struct eigrp_fifo *eigrp_fifo_new(void);
-extern struct eigrp_packet *eigrp_fifo_next(struct eigrp_fifo *);
-extern struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *);
-extern void eigrp_fifo_push(struct eigrp_fifo *, struct eigrp_packet *);
-extern void eigrp_fifo_free(struct eigrp_fifo *);
-extern void eigrp_fifo_reset(struct eigrp_fifo *);
-
-extern void eigrp_send_packet_reliably(struct eigrp_neighbor *);
-
-extern struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *);
-extern uint16_t eigrp_add_internalTLV_to_stream(struct stream *,
-                                               struct eigrp_prefix_entry *);
-extern uint16_t eigrp_add_authTLV_MD5_to_stream(struct stream *,
-                                               struct eigrp_interface *);
-extern uint16_t eigrp_add_authTLV_SHA256_to_stream(struct stream *,
-                                                  struct eigrp_interface *);
-
-extern int eigrp_unack_packet_retrans(struct thread *);
-extern int eigrp_unack_multicast_packet_retrans(struct thread *);
+extern struct eigrp_packet *eigrp_fifo_next(struct eigrp_fifo *fifo);
+extern struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *fifo);
+extern void eigrp_fifo_push(struct eigrp_fifo *fifo, struct eigrp_packet *ep);
+extern void eigrp_fifo_free(struct eigrp_fifo *fifo);
+extern void eigrp_fifo_reset(struct eigrp_fifo *fifo);
+
+extern void eigrp_send_packet_reliably(struct eigrp_neighbor *nbr);
+
+extern struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *s);
+extern uint16_t
+eigrp_add_internalTLV_to_stream(struct stream *s,
+                               struct eigrp_prefix_descriptor *pe);
+extern uint16_t eigrp_add_authTLV_MD5_to_stream(struct stream *s,
+                                               struct eigrp_interface *ei);
+extern uint16_t eigrp_add_authTLV_SHA256_to_stream(struct stream *s,
+                                                  struct eigrp_interface *ei);
+
+extern int eigrp_unack_packet_retrans(struct thread *thread);
+extern int eigrp_unack_multicast_packet_retrans(struct thread *thread);
 
 /*
  * untill there is reason to have their own header, these externs are found in
  * eigrp_hello.c
  */
 extern void eigrp_sw_version_initialize(void);
-extern void eigrp_hello_send(struct eigrp_interface *, uint8_t,
-                            struct in_addr *);
-extern void eigrp_hello_send_ack(struct eigrp_neighbor *);
-extern void eigrp_hello_receive(struct eigrp *, struct ip *,
-                               struct eigrp_header *, struct stream *,
-                               struct eigrp_interface *, int);
-extern int eigrp_hello_timer(struct thread *);
+extern void eigrp_hello_send(struct eigrp_interface *ei, uint8_t flags,
+                            struct in_addr *nbr_addr);
+extern void eigrp_hello_send_ack(struct eigrp_neighbor *nbr);
+extern void eigrp_hello_receive(struct eigrp *eigrp, struct ip *iph,
+                               struct eigrp_header *eigrph, struct stream *s,
+                               struct eigrp_interface *ei, int size);
+extern int eigrp_hello_timer(struct thread *thread);
 
 /*
  * These externs are found in eigrp_update.c
@@ -85,76 +88,83 @@ extern int eigrp_hello_timer(struct thread *);
 extern bool eigrp_update_prefix_apply(struct eigrp *eigrp,
                                      struct eigrp_interface *ei, int in,
                                      struct prefix *prefix);
-extern void eigrp_update_send(struct eigrp_interface *);
-extern void eigrp_update_receive(struct eigrp *, struct ip *,
-                                struct eigrp_header *, struct stream *,
-                                struct eigrp_interface *, int);
-extern void eigrp_update_send_all(struct eigrp *, struct eigrp_interface *);
-extern void eigrp_update_send_init(struct eigrp_neighbor *);
-extern void eigrp_update_send_EOT(struct eigrp_neighbor *);
-extern int eigrp_update_send_GR_thread(struct thread *);
-extern void eigrp_update_send_GR(struct eigrp_neighbor *, enum GR_type,
-                                struct vty *);
-extern void eigrp_update_send_interface_GR(struct eigrp_interface *,
-                                          enum GR_type, struct vty *);
-extern void eigrp_update_send_process_GR(struct eigrp *, enum GR_type,
-                                        struct vty *);
+extern void eigrp_update_send(struct eigrp_interface *ei);
+extern void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
+                                struct eigrp_header *eigrph, struct stream *s,
+                                struct eigrp_interface *ei, int size);
+extern void eigrp_update_send_all(struct eigrp *eigrp,
+                                 struct eigrp_interface *exception);
+extern void eigrp_update_send_init(struct eigrp_neighbor *nbr);
+extern void eigrp_update_send_EOT(struct eigrp_neighbor *nbr);
+extern int eigrp_update_send_GR_thread(struct thread *thread);
+extern void eigrp_update_send_GR(struct eigrp_neighbor *nbr,
+                                enum GR_type gr_type, struct vty *vty);
+extern void eigrp_update_send_interface_GR(struct eigrp_interface *ei,
+                                          enum GR_type gr_type,
+                                          struct vty *vty);
+extern void eigrp_update_send_process_GR(struct eigrp *eigrp,
+                                        enum GR_type gr_type, struct vty *vty);
 
 /*
  * These externs are found in eigrp_query.c
  */
 
-extern void eigrp_send_query(struct eigrp_interface *);
-extern void eigrp_query_receive(struct eigrp *, struct ip *,
-                               struct eigrp_header *, struct stream *,
-                               struct eigrp_interface *, int);
-extern uint32_t eigrp_query_send_all(struct eigrp *);
+extern void eigrp_send_query(struct eigrp_interface *ei);
+extern void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph,
+                               struct eigrp_header *eigrph, struct stream *s,
+                               struct eigrp_interface *ei, int size);
+extern uint32_t eigrp_query_send_all(struct eigrp *eigrp);
 
 /*
  * These externs are found in eigrp_reply.c
  */
-extern void eigrp_send_reply(struct eigrp_neighbor *,
-                            struct eigrp_prefix_entry *);
-extern void eigrp_reply_receive(struct eigrp *, struct ip *,
-                               struct eigrp_header *, struct stream *,
-                               struct eigrp_interface *, int);
+extern void eigrp_send_reply(struct eigrp_neighbor *nbr,
+                            struct eigrp_prefix_descriptor *pe);
+extern void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
+                               struct eigrp_header *eigrph, struct stream *s,
+                               struct eigrp_interface *ei, int size);
 
 /*
  * These externs are found in eigrp_siaquery.c
  */
-extern void eigrp_send_siaquery(struct eigrp_neighbor *,
-                               struct eigrp_prefix_entry *);
-extern void eigrp_siaquery_receive(struct eigrp *, struct ip *,
-                                  struct eigrp_header *, struct stream *,
-                                  struct eigrp_interface *, int);
+extern void eigrp_send_siaquery(struct eigrp_neighbor *nbr,
+                               struct eigrp_prefix_descriptor *pe);
+extern void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
+                                  struct eigrp_header *eigrph,
+                                  struct stream *s, struct eigrp_interface *ei,
+                                  int size);
 
 /*
  * These externs are found in eigrp_siareply.c
  */
-extern void eigrp_send_siareply(struct eigrp_neighbor *,
-                               struct eigrp_prefix_entry *);
-extern void eigrp_siareply_receive(struct eigrp *, struct ip *,
-                                  struct eigrp_header *, struct stream *,
-                                  struct eigrp_interface *, int);
+extern void eigrp_send_siareply(struct eigrp_neighbor *nbr,
+                               struct eigrp_prefix_descriptor *pe);
+extern void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
+                                  struct eigrp_header *eigrph,
+                                  struct stream *s, struct eigrp_interface *ei,
+                                  int size);
 
 extern struct TLV_MD5_Authentication_Type *eigrp_authTLV_MD5_new(void);
-extern void eigrp_authTLV_MD5_free(struct TLV_MD5_Authentication_Type *);
+extern void eigrp_authTLV_MD5_free(struct TLV_MD5_Authentication_Type *authTLV);
 extern struct TLV_SHA256_Authentication_Type *eigrp_authTLV_SHA256_new(void);
-extern void eigrp_authTLV_SHA256_free(struct TLV_SHA256_Authentication_Type *);
-
-extern int eigrp_make_md5_digest(struct eigrp_interface *, struct stream *,
-                                uint8_t);
-extern int eigrp_check_md5_digest(struct stream *,
-                                 struct TLV_MD5_Authentication_Type *,
-                                 struct eigrp_neighbor *, uint8_t);
-extern int eigrp_make_sha256_digest(struct eigrp_interface *, struct stream *,
-                                   uint8_t);
-extern int eigrp_check_sha256_digest(struct stream *,
-                                    struct TLV_SHA256_Authentication_Type *,
-                                    struct eigrp_neighbor *, uint8_t);
-
-
-extern void eigrp_IPv4_InternalTLV_free(struct TLV_IPv4_Internal_type *);
+extern void
+eigrp_authTLV_SHA256_free(struct TLV_SHA256_Authentication_Type *authTLV);
+
+extern int eigrp_make_md5_digest(struct eigrp_interface *ei, struct stream *s,
+                                uint8_t flags);
+extern int eigrp_check_md5_digest(struct stream *s,
+                                 struct TLV_MD5_Authentication_Type *authTLV,
+                                 struct eigrp_neighbor *nbr, uint8_t flags);
+extern int eigrp_make_sha256_digest(struct eigrp_interface *ei,
+                                   struct stream *s, uint8_t flags);
+extern int
+eigrp_check_sha256_digest(struct stream *s,
+                         struct TLV_SHA256_Authentication_Type *authTLV,
+                         struct eigrp_neighbor *nbr, uint8_t flags);
+
+
+extern void
+eigrp_IPv4_InternalTLV_free(struct TLV_IPv4_Internal_type *IPv4_InternalTLV);
 
 extern struct TLV_Sequence_Type *eigrp_SequenceTLV_new(void);
 
index 84dcf5e2d55a081b6dae3685aea58e12b2cf092f..0ab7b59dbb323c777d973aff0e40497c7f3f496b 100644 (file)
@@ -58,7 +58,7 @@ uint32_t eigrp_query_send_all(struct eigrp *eigrp)
 {
        struct eigrp_interface *iface;
        struct listnode *node, *node2, *nnode2;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
        uint32_t counter;
 
        if (eigrp == NULL) {
@@ -118,7 +118,7 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph,
                        dest_addr.family = AF_INET;
                        dest_addr.u.prefix4 = tlv->destination;
                        dest_addr.prefixlen = tlv->prefix_length;
-                       struct eigrp_prefix_entry *dest =
+                       struct eigrp_prefix_descriptor *dest =
                                eigrp_topology_table_lookup_ipv4(
                                        eigrp->topology_table, &dest_addr);
 
@@ -126,9 +126,9 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph,
                         * know)*/
                        if (dest != NULL) {
                                struct eigrp_fsm_action_message msg;
-                               struct eigrp_nexthop_entry *entry =
-                                       eigrp_prefix_entry_lookup(dest->entries,
-                                                                 nbr);
+                               struct eigrp_route_descriptor *entry =
+                                       eigrp_route_descriptor_lookup(
+                                               dest->entries, nbr);
                                msg.packet_type = EIGRP_OPC_QUERY;
                                msg.eigrp = eigrp;
                                msg.data_type = EIGRP_INT;
@@ -164,7 +164,7 @@ void eigrp_send_query(struct eigrp_interface *ei)
        uint16_t length = EIGRP_HEADER_LEN;
        struct listnode *node, *nnode, *node2, *nnode2;
        struct eigrp_neighbor *nbr;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
        bool has_tlv = false;
        bool new_packet = true;
        uint16_t eigrp_mtu = EIGRP_PACKET_MTU(ei->ifp->mtu);
index 26bb27d7ac6e9b30ca898211912d6f196ff09909..d16482173c009da82a418e2b6e472a065e5c7b2f 100644 (file)
 #include "eigrpd/eigrp_memory.h"
 #include "eigrpd/eigrp_errors.h"
 
-void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
+void eigrp_send_reply(struct eigrp_neighbor *nbr,
+                     struct eigrp_prefix_descriptor *pe)
 {
        struct eigrp_packet *ep;
        uint16_t length = EIGRP_HEADER_LEN;
        struct eigrp_interface *ei = nbr->ei;
        struct eigrp *eigrp = ei->eigrp;
-       struct eigrp_prefix_entry *pe2;
+       struct eigrp_prefix_descriptor *pe2;
 
        // TODO: Work in progress
        /* Filtering */
        /* get list from eigrp process */
-       pe2 = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY,
-                     sizeof(struct eigrp_prefix_entry));
-       memcpy(pe2, pe, sizeof(struct eigrp_prefix_entry));
+       pe2 = XCALLOC(MTYPE_EIGRP_PREFIX_DESCRIPTOR,
+                     sizeof(struct eigrp_prefix_descriptor));
+       memcpy(pe2, pe, sizeof(struct eigrp_prefix_descriptor));
 
        if (eigrp_update_prefix_apply(eigrp, ei, EIGRP_FILTER_OUT,
                                      pe2->destination)) {
@@ -122,7 +123,7 @@ void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
                eigrp_send_packet_reliably(nbr);
        }
 
-       XFREE(MTYPE_EIGRP_PREFIX_ENTRY, pe2);
+       XFREE(MTYPE_EIGRP_PREFIX_DESCRIPTOR, pe2);
 }
 
 /*EIGRP REPLY read function*/
@@ -161,7 +162,7 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
                dest_addr.family = AF_INET;
                dest_addr.u.prefix4 = tlv->destination;
                dest_addr.prefixlen = tlv->prefix_length;
-               struct eigrp_prefix_entry *dest =
+               struct eigrp_prefix_descriptor *dest =
                        eigrp_topology_table_lookup_ipv4(eigrp->topology_table,
                                                         &dest_addr);
                /*
@@ -177,8 +178,8 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
                }
 
                struct eigrp_fsm_action_message msg;
-               struct eigrp_nexthop_entry *entry =
-                       eigrp_prefix_entry_lookup(dest->entries, nbr);
+               struct eigrp_route_descriptor *entry =
+                       eigrp_route_descriptor_lookup(dest->entries, nbr);
 
                if (eigrp_update_prefix_apply(eigrp, ei, EIGRP_FILTER_IN,
                                              &dest_addr)) {
index e15f777954aad9e229c096593a90a7c86546dd87..5183e645e596c65123c5e12c7aba52dcb579d12f 100644 (file)
@@ -265,8 +265,8 @@ route_match_metric(void *rule, struct prefix *prefix, route_map_object_t type,
        //  uint32_t *metric;
        //  uint32_t  check;
        //  struct rip_info *rinfo;
-       //  struct eigrp_nexthop_entry *te;
-       //  struct eigrp_prefix_entry *pe;
+       //  struct eigrp_route_descriptor *te;
+       //  struct eigrp_prefix_descriptor *pe;
        //  struct listnode *node, *node2, *nnode, *nnode2;
        //  struct eigrp *e;
        //
index ff383254651a7759fc4bc968ca90d73ee9d7e65a..027700fe11a95322fefcd2d920c303b629bbb6b0 100644 (file)
@@ -87,7 +87,7 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
                        dest_addr.family = AFI_IP;
                        dest_addr.u.prefix4 = tlv->destination;
                        dest_addr.prefixlen = tlv->prefix_length;
-                       struct eigrp_prefix_entry *dest =
+                       struct eigrp_prefix_descriptor *dest =
                                eigrp_topology_table_lookup_ipv4(
                                        eigrp->topology_table, &dest_addr);
 
@@ -95,9 +95,9 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
                         * know)*/
                        if (dest != NULL) {
                                struct eigrp_fsm_action_message msg;
-                               struct eigrp_nexthop_entry *entry =
-                                       eigrp_prefix_entry_lookup(dest->entries,
-                                                                 nbr);
+                               struct eigrp_route_descriptor *entry =
+                                       eigrp_route_descriptor_lookup(
+                                               dest->entries, nbr);
                                msg.packet_type = EIGRP_OPC_SIAQUERY;
                                msg.eigrp = eigrp;
                                msg.data_type = EIGRP_INT;
@@ -114,7 +114,7 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
 }
 
 void eigrp_send_siaquery(struct eigrp_neighbor *nbr,
-                        struct eigrp_prefix_entry *pe)
+                        struct eigrp_prefix_descriptor *pe)
 {
        struct eigrp_packet *ep;
        uint16_t length = EIGRP_HEADER_LEN;
index d3dd123f909cb4f79862e77914b1ae10c370a777..590b224d68ec2c8e5ae2f39e020de05f530eccde 100644 (file)
@@ -86,7 +86,7 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
                        dest_addr.family = AFI_IP;
                        dest_addr.u.prefix4 = tlv->destination;
                        dest_addr.prefixlen = tlv->prefix_length;
-                       struct eigrp_prefix_entry *dest =
+                       struct eigrp_prefix_descriptor *dest =
                                eigrp_topology_table_lookup_ipv4(
                                        eigrp->topology_table, &dest_addr);
 
@@ -94,9 +94,9 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
                         * know)*/
                        if (dest != NULL) {
                                struct eigrp_fsm_action_message msg;
-                               struct eigrp_nexthop_entry *entry =
-                                       eigrp_prefix_entry_lookup(dest->entries,
-                                                                 nbr);
+                               struct eigrp_route_descriptor *entry =
+                                       eigrp_route_descriptor_lookup(
+                                               dest->entries, nbr);
                                msg.packet_type = EIGRP_OPC_SIAQUERY;
                                msg.eigrp = eigrp;
                                msg.data_type = EIGRP_INT;
@@ -113,7 +113,7 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
 }
 
 void eigrp_send_siareply(struct eigrp_neighbor *nbr,
-                        struct eigrp_prefix_entry *pe)
+                        struct eigrp_prefix_descriptor *pe)
 {
        struct eigrp_packet *ep;
        uint16_t length = EIGRP_HEADER_LEN;
index 82bddaaae3bbd5dbe51ecb6f857776278b5e48a3..cddab57dd54ee4c35f8209ffe66bf417d3a92d4b 100644 (file)
 #include "eigrpd/eigrp_const.h"
 #include "eigrpd/eigrp_macros.h"
 
-/* EIGRP master for system wide configuration and variables. */
-struct eigrp_master {
-       /* EIGRP instance. */
-       struct list *eigrp;
-
-       /* EIGRP thread master. */
-       struct thread_master *master;
-
-       /* Zebra interface list. */
-       struct list *iflist;
-
-       /* EIGRP start time. */
-       time_t start_time;
-
-       /* Various EIGRP global configuration. */
-       uint8_t options;
-
-#define EIGRP_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */
-};
-
 struct eigrp_metrics {
        uint32_t delay;
        uint32_t bandwidth;
@@ -68,6 +48,16 @@ struct eigrp_metrics {
        uint8_t flags;
 };
 
+struct eigrp_extdata {
+       uint32_t orig;
+       uint32_t as;
+       uint32_t tag;
+       uint32_t metric;
+       uint16_t reserved;
+       uint8_t protocol;
+       uint8_t flags;
+};
+
 struct eigrp {
        vrf_id_t vrf_id;
 
@@ -450,7 +440,7 @@ enum GR_type { EIGRP_GR_MANUAL, EIGRP_GR_FILTER };
 //---------------------------------------------------------------------------------------------------------------------------------------------
 
 /* EIGRP Topology table node structure */
-struct eigrp_prefix_entry {
+struct eigrp_prefix_descriptor {
        struct list *entries, *rij;
        uint32_t fdistance;                   // FD
        uint32_t rdistance;                   // RD
@@ -473,8 +463,14 @@ struct eigrp_prefix_entry {
 };
 
 /* EIGRP Topology table record structure */
-struct eigrp_nexthop_entry {
-       struct eigrp_prefix_entry *prefix;
+struct eigrp_route_descriptor {
+       uint16_t type;
+       uint16_t afi;
+
+       struct eigrp_prefix_descriptor *prefix;
+       struct eigrp_neighbor *adv_router;
+       struct in_addr nexthop;
+
        uint32_t reported_distance; // distance reported by neighbor
        uint32_t distance;        // sum of reported distance and link cost to
                                    // advertised neighbor
@@ -482,7 +478,9 @@ struct eigrp_nexthop_entry {
        struct eigrp_metrics reported_metric;
        struct eigrp_metrics total_metric;
 
-       struct eigrp_neighbor *adv_router; // ip address of advertising neighbor
+       struct eigrp_metrics metric;
+       struct eigrp_extdata extdata;
+
        uint8_t flags;                     // used for marking successor and FS
 
        struct eigrp_interface *ei; // pointer for case of connected entry
@@ -501,8 +499,8 @@ struct eigrp_fsm_action_message {
        uint8_t packet_type;               // UPDATE, QUERY, SIAQUERY, SIAREPLY
        struct eigrp *eigrp;               // which thread sent mesg
        struct eigrp_neighbor *adv_router; // advertising neighbor
-       struct eigrp_nexthop_entry *entry;
-       struct eigrp_prefix_entry *prefix;
+       struct eigrp_route_descriptor *entry;
+       struct eigrp_prefix_descriptor *prefix;
        msg_data_t data_type; // internal or external tlv type
        struct eigrp_metrics metrics;
        enum metric_change change;
index 2dbee166946f6003f238ea87de71d5ad0e6fd04f..1b7e9fc15bb37a94ed47da75bd260a67bd3fe38c 100644 (file)
@@ -39,6 +39,7 @@
 #include "vty.h"
 #include "lib_errors.h"
 
+#include "eigrpd/eigrp_types.h"
 #include "eigrpd/eigrp_structs.h"
 #include "eigrpd/eigrpd.h"
 #include "eigrpd/eigrp_interface.h"
 #include "eigrpd/eigrp_topology.h"
 #include "eigrpd/eigrp_fsm.h"
 #include "eigrpd/eigrp_memory.h"
+#include "eigrpd/eigrp_metric.h"
 
-static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *,
-                                  struct eigrp_nexthop_entry *);
+static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor *rd1,
+                                     struct eigrp_route_descriptor *rd2);
 
 /*
  * Returns linkedlist used as topology table
@@ -70,14 +72,14 @@ struct route_table *eigrp_topology_new(void)
  * Returns new created toplogy node
  * cmp - assigned function for comparing topology entry
  */
-struct eigrp_prefix_entry *eigrp_prefix_entry_new(void)
+struct eigrp_prefix_descriptor *eigrp_prefix_descriptor_new(void)
 {
-       struct eigrp_prefix_entry *new;
-       new = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY,
-                     sizeof(struct eigrp_prefix_entry));
+       struct eigrp_prefix_descriptor *new;
+       new = XCALLOC(MTYPE_EIGRP_PREFIX_DESCRIPTOR,
+                     sizeof(struct eigrp_prefix_descriptor));
        new->entries = list_new();
        new->rij = list_new();
-       new->entries->cmp = (int (*)(void *, void *))eigrp_nexthop_entry_cmp;
+       new->entries->cmp = (int (*)(void *, void *))eigrp_route_descriptor_cmp;
        new->distance = new->fdistance = new->rdistance = EIGRP_MAX_METRIC;
        new->destination = NULL;
 
@@ -87,8 +89,8 @@ struct eigrp_prefix_entry *eigrp_prefix_entry_new(void)
 /*
  * Topology entry comparison
  */
-static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *entry1,
-                                  struct eigrp_nexthop_entry *entry2)
+static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor *entry1,
+                                     struct eigrp_route_descriptor *entry2)
 {
        if (entry1->distance < entry2->distance)
                return -1;
@@ -102,12 +104,12 @@ static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *entry1,
  * Returns new topology entry
  */
 
-struct eigrp_nexthop_entry *eigrp_nexthop_entry_new(void)
+struct eigrp_route_descriptor *eigrp_route_descriptor_new(void)
 {
-       struct eigrp_nexthop_entry *new;
+       struct eigrp_route_descriptor *new;
 
-       new = XCALLOC(MTYPE_EIGRP_NEXTHOP_ENTRY,
-                     sizeof(struct eigrp_nexthop_entry));
+       new = XCALLOC(MTYPE_EIGRP_ROUTE_DESCRIPTOR,
+                     sizeof(struct eigrp_route_descriptor));
        new->reported_distance = EIGRP_MAX_METRIC;
        new->distance = EIGRP_MAX_METRIC;
 
@@ -126,8 +128,8 @@ void eigrp_topology_free(struct eigrp *eigrp, struct route_table *table)
 /*
  * Adding topology node to topology table
  */
-void eigrp_prefix_entry_add(struct route_table *topology,
-                           struct eigrp_prefix_entry *pe)
+void eigrp_prefix_descriptor_add(struct route_table *topology,
+                                struct eigrp_prefix_descriptor *pe)
 {
        struct route_node *rn;
 
@@ -146,9 +148,9 @@ void eigrp_prefix_entry_add(struct route_table *topology,
 /*
  * Adding topology entry to topology node
  */
-void eigrp_nexthop_entry_add(struct eigrp *eigrp,
-                            struct eigrp_prefix_entry *node,
-                            struct eigrp_nexthop_entry *entry)
+void eigrp_route_descriptor_add(struct eigrp *eigrp,
+                               struct eigrp_prefix_descriptor *node,
+                               struct eigrp_route_descriptor *entry)
 {
        struct list *l = list_new();
 
@@ -168,10 +170,11 @@ void eigrp_nexthop_entry_add(struct eigrp *eigrp,
 /*
  * Deleting topology node from topology table
  */
-void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table,
-                              struct eigrp_prefix_entry *pe)
+void eigrp_prefix_descriptor_delete(struct eigrp *eigrp,
+                                   struct route_table *table,
+                                   struct eigrp_prefix_descriptor *pe)
 {
-       struct eigrp_nexthop_entry *ne;
+       struct eigrp_route_descriptor *ne;
        struct listnode *node, *nnode;
        struct route_node *rn;
 
@@ -189,7 +192,7 @@ void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table,
        listnode_delete(eigrp->topology_changes_internalIPV4, pe);
 
        for (ALL_LIST_ELEMENTS(pe->entries, node, nnode, ne))
-               eigrp_nexthop_entry_delete(eigrp, pe, ne);
+               eigrp_route_descriptor_delete(eigrp, pe, ne);
        list_delete(&pe->entries);
        list_delete(&pe->rij);
        eigrp_zebra_route_delete(eigrp, pe->destination);
@@ -198,20 +201,20 @@ void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table,
        rn->info = NULL;
        route_unlock_node(rn); // Lookup above
        route_unlock_node(rn); // Initial creation
-       XFREE(MTYPE_EIGRP_PREFIX_ENTRY, pe);
+       XFREE(MTYPE_EIGRP_PREFIX_DESCRIPTOR, pe);
 }
 
 /*
  * Deleting topology entry from topology node
  */
-void eigrp_nexthop_entry_delete(struct eigrp *eigrp,
-                               struct eigrp_prefix_entry *node,
-                               struct eigrp_nexthop_entry *entry)
+void eigrp_route_descriptor_delete(struct eigrp *eigrp,
+                                  struct eigrp_prefix_descriptor *node,
+                                  struct eigrp_route_descriptor *entry)
 {
        if (listnode_lookup(node->entries, entry) != NULL) {
                listnode_delete(node->entries, entry);
                eigrp_zebra_route_delete(eigrp, node->destination);
-               XFREE(MTYPE_EIGRP_NEXTHOP_ENTRY, entry);
+               XFREE(MTYPE_EIGRP_ROUTE_DESCRIPTOR, entry);
        }
 }
 
@@ -222,7 +225,7 @@ void eigrp_topology_delete_all(struct eigrp *eigrp,
                               struct route_table *topology)
 {
        struct route_node *rn;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
 
        for (rn = route_top(topology); rn; rn = route_next(rn)) {
                pe = rn->info;
@@ -230,15 +233,15 @@ void eigrp_topology_delete_all(struct eigrp *eigrp,
                if (!pe)
                        continue;
 
-               eigrp_prefix_entry_delete(eigrp, topology, pe);
+               eigrp_prefix_descriptor_delete(eigrp, topology, pe);
        }
 }
 
-struct eigrp_prefix_entry *
+struct eigrp_prefix_descriptor *
 eigrp_topology_table_lookup_ipv4(struct route_table *table,
                                 struct prefix *address)
 {
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
        struct route_node *rn;
 
        rn = route_node_lookup(table, address);
@@ -259,14 +262,15 @@ eigrp_topology_table_lookup_ipv4(struct route_table *table,
  * That way we can clean up all the list_new and list_delete's
  * that we are doing.  DBS
  */
-struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node)
+struct list *
+eigrp_topology_get_successor(struct eigrp_prefix_descriptor *table_node)
 {
        struct list *successors = list_new();
-       struct eigrp_nexthop_entry *data;
+       struct eigrp_route_descriptor *data;
        struct listnode *node1, *node2;
 
        for (ALL_LIST_ELEMENTS(table_node->entries, node1, node2, data)) {
-               if (data->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) {
+               if (data->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG) {
                        listnode_add(successors, data);
                }
        }
@@ -283,7 +287,7 @@ struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node)
 }
 
 struct list *
-eigrp_topology_get_successor_max(struct eigrp_prefix_entry *table_node,
+eigrp_topology_get_successor_max(struct eigrp_prefix_descriptor *table_node,
                                 unsigned int maxpaths)
 {
        struct list *successors = eigrp_topology_get_successor(table_node);
@@ -300,10 +304,10 @@ eigrp_topology_get_successor_max(struct eigrp_prefix_entry *table_node,
        return successors;
 }
 
-struct eigrp_nexthop_entry *
-eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *nbr)
+struct eigrp_route_descriptor *
+eigrp_route_descriptor_lookup(struct list *entries, struct eigrp_neighbor *nbr)
 {
-       struct eigrp_nexthop_entry *data;
+       struct eigrp_route_descriptor *data;
        struct listnode *node, *nnode;
        for (ALL_LIST_ELEMENTS(entries, node, nnode, data)) {
                if (data->adv_router == nbr) {
@@ -319,8 +323,8 @@ struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp,
                                            struct eigrp_neighbor *nbr)
 {
        struct listnode *node2, *node22;
-       struct eigrp_nexthop_entry *entry;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_route_descriptor *entry;
+       struct eigrp_prefix_descriptor *pe;
        struct route_node *rn;
 
        /* create new empty list for prefixes storage */
@@ -348,8 +352,8 @@ enum metric_change
 eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg)
 {
        struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
-       struct eigrp_nexthop_entry *entry = msg->entry;
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
+       struct eigrp_route_descriptor *entry = msg->entry;
        enum metric_change change = METRIC_SAME;
        uint32_t new_reported_distance;
 
@@ -413,7 +417,7 @@ distance_done:
 
 void eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
 {
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
        struct route_node *rn;
 
        if (!eigrp)
@@ -430,10 +434,10 @@ void eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
 }
 
 void eigrp_topology_update_node_flags(struct eigrp *eigrp,
-                                     struct eigrp_prefix_entry *dest)
+                                     struct eigrp_prefix_descriptor *dest)
 {
        struct listnode *node;
-       struct eigrp_nexthop_entry *entry;
+       struct eigrp_route_descriptor *entry;
 
        for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) {
                if (entry->reported_distance < dest->fdistance) {
@@ -444,29 +448,29 @@ void eigrp_topology_update_node_flags(struct eigrp *eigrp,
                            && entry->distance != EIGRP_MAX_METRIC) {
                                // is successor
                                entry->flags |=
-                                       EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+                                       EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
                                entry->flags &=
-                                       ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
+                                       ~EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG;
                        } else {
                                // is feasible successor only
                                entry->flags |=
-                                       EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
+                                       EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG;
                                entry->flags &=
-                                       ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+                                       ~EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
                        }
                } else {
-                       entry->flags &= ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
-                       entry->flags &= ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+                       entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG;
+                       entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
                }
        }
 }
 
 void eigrp_update_routing_table(struct eigrp *eigrp,
-                               struct eigrp_prefix_entry *prefix)
+                               struct eigrp_prefix_descriptor *prefix)
 {
        struct list *successors;
        struct listnode *node;
-       struct eigrp_nexthop_entry *entry;
+       struct eigrp_route_descriptor *entry;
 
        successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
 
@@ -474,13 +478,13 @@ void eigrp_update_routing_table(struct eigrp *eigrp,
                eigrp_zebra_route_add(eigrp, prefix->destination, successors,
                                      prefix->fdistance);
                for (ALL_LIST_ELEMENTS_RO(successors, node, entry))
-                       entry->flags |= EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
+                       entry->flags |= EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG;
 
                list_delete(&successors);
        } else {
                eigrp_zebra_route_delete(eigrp, prefix->destination);
                for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry))
-                       entry->flags &= ~EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
+                       entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG;
        }
 }
 
@@ -488,8 +492,8 @@ void eigrp_topology_neighbor_down(struct eigrp *eigrp,
                                  struct eigrp_neighbor *nbr)
 {
        struct listnode *node2, *node22;
-       struct eigrp_prefix_entry *pe;
-       struct eigrp_nexthop_entry *entry;
+       struct eigrp_prefix_descriptor *pe;
+       struct eigrp_route_descriptor *entry;
        struct route_node *rn;
 
        for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
@@ -521,18 +525,18 @@ void eigrp_topology_neighbor_down(struct eigrp *eigrp,
 
 void eigrp_update_topology_table_prefix(struct eigrp *eigrp,
                                        struct route_table *table,
-                                       struct eigrp_prefix_entry *prefix)
+                                       struct eigrp_prefix_descriptor *prefix)
 {
        struct listnode *node1, *node2;
 
-       struct eigrp_nexthop_entry *entry;
+       struct eigrp_route_descriptor *entry;
        for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry)) {
                if (entry->distance == EIGRP_MAX_METRIC) {
-                       eigrp_nexthop_entry_delete(eigrp, prefix, entry);
+                       eigrp_route_descriptor_delete(eigrp, prefix, entry);
                }
        }
        if (prefix->distance == EIGRP_MAX_METRIC
            && prefix->nt != EIGRP_TOPOLOGY_TYPE_CONNECTED) {
-               eigrp_prefix_entry_delete(eigrp, table, prefix);
+               eigrp_prefix_descriptor_delete(eigrp, table, prefix);
        }
 }
index 718cece40383ad9e814b18106982ea5d26b39b46..26fa1a11b0be1ed54317c8068bb3dc4a707368a5 100644 (file)
 /* EIGRP Topology table related functions. */
 extern struct route_table *eigrp_topology_new(void);
 extern void eigrp_topology_init(struct route_table *table);
-extern struct eigrp_prefix_entry *eigrp_prefix_entry_new(void);
-extern struct eigrp_nexthop_entry *eigrp_nexthop_entry_new(void);
+extern struct eigrp_prefix_descriptor *eigrp_prefix_descriptor_new(void);
+extern struct eigrp_route_descriptor *eigrp_route_descriptor_new(void);
 extern void eigrp_topology_free(struct eigrp *eigrp, struct route_table *table);
-extern void eigrp_prefix_entry_add(struct route_table *table,
-                                  struct eigrp_prefix_entry *pe);
-extern void eigrp_nexthop_entry_add(struct eigrp *eigrp,
-                                   struct eigrp_prefix_entry *pe,
-                                   struct eigrp_nexthop_entry *ne);
-extern void eigrp_prefix_entry_delete(struct eigrp *eigrp,
-                                     struct route_table *table,
-                                     struct eigrp_prefix_entry *pe);
-extern void eigrp_nexthop_entry_delete(struct eigrp *eigrp,
-                                      struct eigrp_prefix_entry *pe,
-                                      struct eigrp_nexthop_entry *ne);
+extern void eigrp_prefix_descriptor_add(struct route_table *table,
+                                       struct eigrp_prefix_descriptor *pe);
+extern void eigrp_route_descriptor_add(struct eigrp *eigrp,
+                                      struct eigrp_prefix_descriptor *pe,
+                                      struct eigrp_route_descriptor *ne);
+extern void eigrp_prefix_descriptor_delete(struct eigrp *eigrp,
+                                          struct route_table *table,
+                                          struct eigrp_prefix_descriptor *pe);
+extern void eigrp_route_descriptor_delete(struct eigrp *eigrp,
+                                         struct eigrp_prefix_descriptor *pe,
+                                         struct eigrp_route_descriptor *ne);
 extern void eigrp_topology_delete_all(struct eigrp *eigrp,
                                      struct route_table *table);
-extern struct eigrp_prefix_entry *
+extern struct eigrp_prefix_descriptor *
 eigrp_topology_table_lookup_ipv4(struct route_table *table, struct prefix *p);
-extern struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *pe);
 extern struct list *
-eigrp_topology_get_successor_max(struct eigrp_prefix_entry *pe,
+eigrp_topology_get_successor(struct eigrp_prefix_descriptor *pe);
+extern struct list *
+eigrp_topology_get_successor_max(struct eigrp_prefix_descriptor *pe,
                                 unsigned int maxpaths);
-extern struct eigrp_nexthop_entry *
-eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *neigh);
+extern struct eigrp_route_descriptor *
+eigrp_route_descriptor_lookup(struct list *entries,
+                             struct eigrp_neighbor *neigh);
 extern struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp,
                                                   struct eigrp_neighbor *n);
 extern void eigrp_topology_update_all_node_flags(struct eigrp *eigrp);
-extern void eigrp_topology_update_node_flags(struct eigrp *eigrp,
-                                            struct eigrp_prefix_entry *pe);
+extern void
+eigrp_topology_update_node_flags(struct eigrp *eigrp,
+                                struct eigrp_prefix_descriptor *pe);
 extern enum metric_change
 eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg);
 extern void eigrp_update_routing_table(struct eigrp *eigrp,
-                                      struct eigrp_prefix_entry *pe);
+                                      struct eigrp_prefix_descriptor *pe);
 extern void eigrp_topology_neighbor_down(struct eigrp *eigrp,
                                         struct eigrp_neighbor *neigh);
-extern void eigrp_update_topology_table_prefix(struct eigrp *eigrp,
-                                              struct route_table *table,
-                                              struct eigrp_prefix_entry *pe);
+extern void
+eigrp_update_topology_table_prefix(struct eigrp *eigrp,
+                                  struct route_table *table,
+                                  struct eigrp_prefix_descriptor *pe);
 
 #endif
diff --git a/eigrpd/eigrp_types.h b/eigrpd/eigrp_types.h
new file mode 100644 (file)
index 0000000..bd65107
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * EIGRP Definition of Data Types
+ * Copyright (C) 2018
+ * Authors:
+ *   Donnie Savage
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _ZEBRA_EIGRP_TYPES_H_
+#define _ZEBRA_EIGRP_TYPES_H_
+
+typedef uint64_t eigrp_bandwidth_t;
+typedef uint64_t eigrp_delay_t;
+typedef uint64_t eigrp_metric_t;
+typedef uint32_t eigrp_scaled_t;
+
+typedef uint32_t eigrp_system_metric_t;
+typedef uint32_t eigrp_system_delay_t;
+typedef uint32_t eigrp_system_bandwidth_t;
+
+#endif /* _ZEBRA_EIGRP_TYPES_H_ */
index cd30eb5ab5f60fe0d4110ecfaed468aa70ae73bb..91f3b3218bca44063789d308990488b111a3a345 100644 (file)
@@ -49,6 +49,7 @@
 #include "routemap.h"
 #include "vty.h"
 
+#include "eigrpd/eigrp_types.h"
 #include "eigrpd/eigrp_structs.h"
 #include "eigrpd/eigrpd.h"
 #include "eigrpd/eigrp_interface.h"
@@ -62,6 +63,7 @@
 #include "eigrpd/eigrp_fsm.h"
 #include "eigrpd/eigrp_network.h"
 #include "eigrpd/eigrp_memory.h"
+#include "eigrpd/eigrp_metric.h"
 
 bool eigrp_update_prefix_apply(struct eigrp *eigrp, struct eigrp_interface *ei,
                               int in, struct prefix *prefix)
@@ -101,11 +103,12 @@ bool eigrp_update_prefix_apply(struct eigrp *eigrp, struct eigrp_interface *ei,
  * Function is used for removing received prefix
  * from list of neighbor prefixes
  */
-static void remove_received_prefix_gr(struct list *nbr_prefixes,
-                                     struct eigrp_prefix_entry *recv_prefix)
+static void
+remove_received_prefix_gr(struct list *nbr_prefixes,
+                         struct eigrp_prefix_descriptor *recv_prefix)
 {
        struct listnode *node1, *node11;
-       struct eigrp_prefix_entry *prefix = NULL;
+       struct eigrp_prefix_descriptor *prefix = NULL;
 
        /* iterate over all prefixes in list */
        for (ALL_LIST_ELEMENTS(nbr_prefixes, node1, node11, prefix)) {
@@ -136,7 +139,7 @@ static void eigrp_update_receive_GR_ask(struct eigrp *eigrp,
                                        struct list *nbr_prefixes)
 {
        struct listnode *node1;
-       struct eigrp_prefix_entry *prefix;
+       struct eigrp_prefix_descriptor *prefix;
        struct eigrp_fsm_action_message fsm_msg;
 
        /* iterate over all prefixes which weren't advertised by neighbor */
@@ -148,8 +151,8 @@ static void eigrp_update_receive_GR_ask(struct eigrp *eigrp,
                /* set delay to MAX */
                fsm_msg.metrics.delay = EIGRP_MAX_METRIC;
 
-               struct eigrp_nexthop_entry *entry =
-                       eigrp_prefix_entry_lookup(prefix->entries, nbr);
+               struct eigrp_route_descriptor *entry =
+                       eigrp_route_descriptor_lookup(prefix->entries, nbr);
 
                fsm_msg.packet_type = EIGRP_OPC_UPDATE;
                fsm_msg.eigrp = eigrp;
@@ -172,8 +175,8 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
 {
        struct eigrp_neighbor *nbr;
        struct TLV_IPv4_Internal_type *tlv;
-       struct eigrp_prefix_entry *pe;
-       struct eigrp_nexthop_entry *ne;
+       struct eigrp_prefix_descriptor *pe;
+       struct eigrp_route_descriptor *ne;
        uint32_t flags;
        uint16_t type;
        uint16_t length;
@@ -304,7 +307,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
                        dest_addr.family = AF_INET;
                        dest_addr.u.prefix4 = tlv->destination;
                        dest_addr.prefixlen = tlv->prefix_length;
-                       struct eigrp_prefix_entry *dest =
+                       struct eigrp_prefix_descriptor *dest =
                                eigrp_topology_table_lookup_ipv4(
                                        eigrp->topology_table, &dest_addr);
 
@@ -317,9 +320,9 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
                                                                  dest);
 
                                struct eigrp_fsm_action_message msg;
-                               struct eigrp_nexthop_entry *entry =
-                                       eigrp_prefix_entry_lookup(dest->entries,
-                                                                 nbr);
+                               struct eigrp_route_descriptor *entry =
+                                       eigrp_route_descriptor_lookup(
+                                               dest->entries, nbr);
 
                                msg.packet_type = EIGRP_OPC_UPDATE;
                                msg.eigrp = eigrp;
@@ -331,7 +334,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
                                eigrp_fsm_event(&msg);
                        } else {
                                /*Here comes topology information save*/
-                               pe = eigrp_prefix_entry_new();
+                               pe = eigrp_prefix_descriptor_new();
                                pe->serno = eigrp->serno;
                                pe->destination =
                                        (struct prefix *)prefix_ipv4_new();
@@ -340,7 +343,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
                                pe->state = EIGRP_FSM_STATE_PASSIVE;
                                pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE;
 
-                               ne = eigrp_nexthop_entry_new();
+                               ne = eigrp_route_descriptor_new();
                                ne->ei = ei;
                                ne->adv_router = nbr;
                                ne->reported_metric = tlv->metric;
@@ -361,11 +364,12 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
                                pe->fdistance = pe->distance = pe->rdistance =
                                        ne->distance;
                                ne->prefix = pe;
-                               ne->flags = EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+                               ne->flags =
+                                       EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
 
-                               eigrp_prefix_entry_add(eigrp->topology_table,
-                                                      pe);
-                               eigrp_nexthop_entry_add(eigrp, pe, ne);
+                               eigrp_prefix_descriptor_add(
+                                       eigrp->topology_table, pe);
+                               eigrp_route_descriptor_add(eigrp, pe, ne);
                                pe->distance = pe->fdistance = pe->rdistance =
                                        ne->distance;
                                pe->reported_metric = ne->total_metric;
@@ -527,8 +531,8 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr)
 {
        struct eigrp_packet *ep;
        uint16_t length = EIGRP_HEADER_LEN;
-       struct eigrp_nexthop_entry *te;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_route_descriptor *te;
+       struct eigrp_prefix_descriptor *pe;
        struct listnode *node2, *nnode2;
        struct eigrp_interface *ei = nbr->ei;
        struct eigrp *eigrp = ei->eigrp;
@@ -600,7 +604,7 @@ void eigrp_update_send(struct eigrp_interface *ei)
 {
        struct eigrp_packet *ep;
        struct listnode *node, *nnode;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
        uint8_t has_tlv;
        struct eigrp *eigrp = ei->eigrp;
        struct prefix *dest_addr;
@@ -626,7 +630,7 @@ void eigrp_update_send(struct eigrp_interface *ei)
        has_tlv = 0;
        for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node,
                               nnode, pe)) {
-               struct eigrp_nexthop_entry *ne;
+               struct eigrp_route_descriptor *ne;
 
                if (!(pe->req_action & EIGRP_FSM_NEED_UPDATE))
                        continue;
@@ -707,7 +711,7 @@ void eigrp_update_send_all(struct eigrp *eigrp,
 {
        struct eigrp_interface *iface;
        struct listnode *node, *node2, *nnode2;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
 
        for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface)) {
                if (iface != exception) {
@@ -745,7 +749,7 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
 {
        struct eigrp_packet *ep;
        uint16_t length = EIGRP_HEADER_LEN;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
        struct prefix *dest_addr;
        struct eigrp_interface *ei = nbr->ei;
        struct eigrp *eigrp = ei->eigrp;
@@ -837,8 +841,8 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
                        /* prepare message for FSM */
                        struct eigrp_fsm_action_message fsm_msg;
 
-                       struct eigrp_nexthop_entry *entry =
-                               eigrp_prefix_entry_lookup(pe->entries, nbr);
+                       struct eigrp_route_descriptor *entry =
+                               eigrp_route_descriptor_lookup(pe->entries, nbr);
 
                        fsm_msg.packet_type = EIGRP_OPC_UPDATE;
                        fsm_msg.eigrp = eigrp;
@@ -956,7 +960,7 @@ int eigrp_update_send_GR_thread(struct thread *thread)
 void eigrp_update_send_GR(struct eigrp_neighbor *nbr, enum GR_type gr_type,
                          struct vty *vty)
 {
-       struct eigrp_prefix_entry *pe2;
+       struct eigrp_prefix_descriptor *pe2;
        struct list *prefixes;
        struct route_node *rn;
        struct eigrp_interface *ei = nbr->ei;
index 66dfbaa5385dc5dc98050d35bff73c4c11b6ebf7..0809ac2cf08e63cb07dec3de540433d419a2b0c0 100644 (file)
 #include "eigrpd/eigrp_vty_clippy.c"
 #endif
 
-static void eigrp_vty_display_prefix_entry(struct vty *vty,
-                                          struct eigrp *eigrp,
-                                          struct eigrp_prefix_entry *pe,
+static void eigrp_vty_display_prefix_entry(struct vty *vty, struct eigrp *eigrp,
+                                          struct eigrp_prefix_descriptor *pe,
                                           bool all)
 {
        bool first = true;
-       struct eigrp_nexthop_entry *te;
+       struct eigrp_route_descriptor *te;
        struct listnode *node;
 
        for (ALL_LIST_ELEMENTS_RO(pe->entries, node, te)) {
                if (all
-                   || (((te->flags
-                         & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)
-                        == EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)
-                       || ((te->flags
-                            & EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG)
-                           == EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG))) {
-                       show_ip_eigrp_nexthop_entry(vty, eigrp, te,
-                                                   &first);
+                   || (((te->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)
+                        == EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)
+                       || ((te->flags & EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG)
+                           == EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG))) {
+                       show_ip_eigrp_route_descriptor(vty, eigrp, te, &first);
                        first = false;
                }
        }
@@ -104,7 +100,7 @@ static struct eigrp *eigrp_vty_get_eigrp(struct vty *vty, const char *vrf_name)
 static void eigrp_topology_helper(struct vty *vty, struct eigrp *eigrp,
                                  const char *all)
 {
-       struct eigrp_prefix_entry *tn;
+       struct eigrp_prefix_descriptor *tn;
        struct route_node *rn;
 
        show_ip_eigrp_topology_header(vty, eigrp);
@@ -168,7 +164,7 @@ DEFPY (show_ip_eigrp_topology,
        "For a specific prefix\n")
 {
        struct eigrp *eigrp;
-       struct eigrp_prefix_entry *tn;
+       struct eigrp_prefix_descriptor *tn;
        struct route_node *rn;
        struct prefix cmp;
 
diff --git a/eigrpd/eigrp_yang.h b/eigrpd/eigrp_yang.h
new file mode 100644 (file)
index 0000000..a95e531
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * EIGRP YANG Functions.
+ * Copyright (C) 2019
+ * Authors:
+ *   Donnie Savage
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _EIGRP_YANG_H_
+#define _EIGRP_YANG_H_
+
+/*Prototypes*/
+
+/* eigrp_northbound.c */
+extern const struct frr_yang_module_info frr_eigrpd_info;
+
+#endif /*EIGRP_YANG_H_ */
index 0795fbd6df510892b4c3226d8bb0eb89bcb09536..e79123e6b4cf30b28869c42c8571615e03470344 100644 (file)
@@ -41,6 +41,7 @@
 #include "log.h"
 #include "nexthop.h"
 
+#include "eigrpd/eigrp_types.h"
 #include "eigrpd/eigrp_structs.h"
 #include "eigrpd/eigrpd.h"
 #include "eigrpd/eigrp_interface.h"
@@ -52,6 +53,7 @@
 #include "eigrpd/eigrp_network.h"
 #include "eigrpd/eigrp_topology.h"
 #include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_metric.h"
 
 static int eigrp_interface_address_add(ZAPI_CALLBACK_ARGS);
 static int eigrp_interface_address_delete(ZAPI_CALLBACK_ARGS);
@@ -194,7 +196,7 @@ void eigrp_zebra_route_add(struct eigrp *eigrp, struct prefix *p,
 {
        struct zapi_route api;
        struct zapi_nexthop *api_nh;
-       struct eigrp_nexthop_entry *te;
+       struct eigrp_route_descriptor *te;
        struct listnode *node;
        int count = 0;
 
index 6b4d45d1fc271e45a15ac83b8c60b5a56582651e..01173768ba99c865f05dc1ce450c3d83499126e9 100644 (file)
 #define EIGRP_MAJOR_VERSION     1
 #define EIGRP_MINOR_VERSION    2
 
+#define EIGRP_TLV_32B_VERSION 1 /* Original 32bit scaled metrics */
+#define EIGRP_TLV_64B_VERSION 2 /* Current 64bit 'wide' metrics */
+#define EIGRP_TLV_MTR_VERSION 3 /* MTR TLVs with 32bit metric *Not Supported */
+#define EIGRP_TLV_SAF_VERSION 4 /* SAF TLVs with 64bit metric *Not Supported */
+
+struct eigrp_master {
+       /* EIGRP instance. */
+       struct list *eigrp;
+
+       /* EIGRP thread master. */
+       struct thread_master *master;
+
+       /* Zebra interface list. */
+       struct list *iflist;
+
+       /* EIGRP start time. */
+       time_t start_time;
+
+       /* Various EIGRP global configuration. */
+       uint8_t options;
+
+#define EIGRP_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */
+};
+
 /* Extern variables. */
 extern struct zclient *zclient;
 extern struct thread_master *master;
@@ -46,57 +70,10 @@ extern struct zebra_privs_t eigrpd_privs;
 /* Prototypes */
 extern void eigrp_master_init(void);
 extern void eigrp_terminate(void);
-extern void eigrp_finish_final(struct eigrp *);
-extern void eigrp_finish(struct eigrp *);
+extern void eigrp_finish_final(struct eigrp *eigrp);
+extern void eigrp_finish(struct eigrp *eigrp);
 extern struct eigrp *eigrp_get(uint16_t as, vrf_id_t vrf_id);
 extern struct eigrp *eigrp_lookup(vrf_id_t vrf_id);
-extern void eigrp_router_id_update(struct eigrp *);
-
-/* eigrp_cli.c */
-extern void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode,
-                                 bool show_defaults);
-extern void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode);
-extern void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode,
-                                    bool show_defaults);
-extern void eigrp_cli_show_passive_interface(struct vty *vty,
-                                            struct lyd_node *dnode,
-                                            bool show_defaults);
-extern void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode,
-                                      bool show_defaults);
-extern void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode,
-                                   bool show_defaults);
-extern void eigrp_cli_show_maximum_paths(struct vty *vty,
-                                        struct lyd_node *dnode,
-                                        bool show_defaults);
-extern void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode,
-                                  bool show_defaults);
-extern void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode,
-                                  bool show_defaults);
-extern void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode,
-                                   bool show_defaults);
-extern void eigrp_cli_show_redistribute(struct vty *vty,
-                                       struct lyd_node *dnode,
-                                       bool show_defaults);
-extern void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode,
-                                bool show_defaults);
-extern void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode,
-                                    bool show_defaults);
-extern void eigrp_cli_show_hello_interval(struct vty *vty,
-                                         struct lyd_node *dnode,
-                                         bool show_defaults);
-extern void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode,
-                                    bool show_defaults);
-extern void eigrp_cli_show_summarize_address(struct vty *vty,
-                                            struct lyd_node *dnode,
-                                            bool show_defaults);
-extern void eigrp_cli_show_authentication(struct vty *vty,
-                                         struct lyd_node *dnode,
-                                         bool show_defaults);
-extern void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode,
-                                   bool show_defaults);
-extern void eigrp_cli_init(void);
-
-/* eigrp_northbound.c */
-extern const struct frr_yang_module_info frr_eigrpd_info;
+extern void eigrp_router_id_update(struct eigrp *eigrp);
 
 #endif /* _ZEBRA_EIGRPD_H */
index 98f39440c36d8cc0b7935c67432a2cc00efa686e..13c9f7f8aeb072d261bfa779584490432acad41b 100644 (file)
@@ -25,6 +25,7 @@ eigrpd_libeigrp_a_SOURCES = \
        eigrpd/eigrp_hello.c \
        eigrpd/eigrp_interface.c \
        eigrpd/eigrp_memory.c \
+       eigrpd/eigrp_metric.c \
        eigrpd/eigrp_neighbor.c \
        eigrpd/eigrp_network.c \
        eigrpd/eigrp_northbound.c \
@@ -55,6 +56,7 @@ clippy_scan += \
        # end
 
 noinst_HEADERS += \
+       eigrpd/eigrp_cli.h \
        eigrpd/eigrp_const.h \
        eigrpd/eigrp_errors.h \
        eigrpd/eigrp_filter.h \
@@ -62,13 +64,16 @@ noinst_HEADERS += \
        eigrpd/eigrp_interface.h \
        eigrpd/eigrp_macros.h \
        eigrpd/eigrp_memory.h \
+       eigrpd/eigrp_metric.h \
        eigrpd/eigrp_neighbor.h \
        eigrpd/eigrp_network.h \
        eigrpd/eigrp_packet.h \
        eigrpd/eigrp_snmp.h \
        eigrpd/eigrp_structs.h \
+       eigrpd/eigrp_types.h \
        eigrpd/eigrp_vrf.h \
        eigrpd/eigrp_vty.h \
+       eigrpd/eigrp_yang.h \
        eigrpd/eigrp_zebra.h \
        # end
 
index 50011d55ecc86a9661439487494f56bee2dc57ad..fb79481cb2a627d3d9e326385846a08517db2025 100644 (file)
@@ -293,15 +293,4 @@ struct br_mcast_stats {
        __u64 mcast_bytes[BR_MCAST_DIR_SIZE];
        __u64 mcast_packets[BR_MCAST_DIR_SIZE];
 };
-
-/* FDB notification bits for NDA_NOTIFY:
- * - BR_FDB_NFY_STATIC - notify on activity/expire even for a static entry
- * - BR_FDB_NFY_INACTIVE - mark as inactive to avoid double notification,
- *                         used with BR_FDB_NFY_STATIC (kernel controlled)
- */
-enum {
-       BR_FDB_NFY_STATIC,
-       BR_FDB_NFY_INACTIVE,
-       BR_FDB_NFY_MAX
-};
 #endif /* _UAPI_LINUX_IF_BRIDGE_H */
index c06fe708f79190e5daf754a1378c67714206c0d4..581af73c7fe2fc6c001d5d4ea1024dae181937db 100644 (file)
@@ -30,7 +30,7 @@ enum {
        NDA_SRC_VNI,
        NDA_PROTOCOL,  /* Originator of entry */
        NDA_NH_ID,
-       NDA_NOTIFY,
+       NDA_FDB_EXT_ATTRS,
        NDA_EXT_FLAGS,
        __NDA_MAX
 };
@@ -178,4 +178,27 @@ enum {
 };
 #define NDTA_MAX (__NDTA_MAX - 1)
 
+/* FDB activity notification bits used in NFEA_ACTIVITY_NOTIFY:
+ * - FDB_NOTIFY_BIT - notify on activity/expire for any entry
+ * - FDB_NOTIFY_INACTIVE_BIT - mark as inactive to avoid multiple notifications
+ */
+enum {
+       FDB_NOTIFY_BIT          = (1 << 0),
+       FDB_NOTIFY_INACTIVE_BIT = (1 << 1)
+};
+
+/* embedded into NDA_FDB_EXT_ATTRS:
+ * [NDA_FDB_EXT_ATTRS] = {
+ *     [NFEA_ACTIVITY_NOTIFY]
+ *     ...
+ * }
+ */
+enum {
+       NFEA_UNSPEC,
+       NFEA_ACTIVITY_NOTIFY,
+       NFEA_DONT_REFRESH,
+       __NFEA_MAX
+};
+#define NFEA_MAX (__NFEA_MAX - 1)
+
 #endif
index 9599077771749b5a66a33d4403d3399e4552a8be..454da99e094fd69fffa6ae3680046fba9e09b06e 100644 (file)
@@ -215,7 +215,7 @@ int isis_sock_init(struct isis_circuit *circuit)
 
 int isis_recv_pdu_bcast(struct isis_circuit *circuit, uint8_t *ssnpa)
 {
-       int bytesread = 0, bytestoread, offset, one = 1;
+       int bytesread = 0, bytestoread = 0, offset, one = 1;
        uint8_t *buff_ptr;
        struct bpf_hdr *bpf_hdr;
 
index 72c17a4c70c57fc2dc068e7c8a63dca44887097f..4aac3f8880cebb8fd1e47535589bb1cc6f616b5c 100644 (file)
@@ -140,6 +140,8 @@ struct isis_circuit *isis_circuit_new(struct isis *isis)
 #endif /* ifndef FABRICD */
 
        circuit_mt_init(circuit);
+       isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL1);
+       isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL2);
 
        QOBJ_REG(circuit, isis_circuit);
 
@@ -156,6 +158,8 @@ void isis_circuit_del(struct isis_circuit *circuit)
        isis_circuit_if_unbind(circuit, circuit->interface);
 
        circuit_mt_finish(circuit);
+       isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL1);
+       isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL2);
 
        /* and lastly the circuit itself */
        XFREE(MTYPE_ISIS_CIRCUIT, circuit);
index abb09f84ef738233ffcf30d20998248637e2e38e..3387232da2a7af5e0f04bb665a87f43c17276529 100644 (file)
@@ -141,6 +141,10 @@ struct isis_circuit {
        bool disable_threeway_adj;
        struct bfd_info *bfd_info;
        struct ldp_sync_info *ldp_sync_info;
+       bool lfa_protection[ISIS_LEVELS];
+       bool rlfa_protection[ISIS_LEVELS];
+       uint32_t rlfa_max_metric[ISIS_LEVELS];
+       struct hash *lfa_excluded_ifaces[ISIS_LEVELS];
        bool tilfa_protection[ISIS_LEVELS];
        bool tilfa_node_protection[ISIS_LEVELS];
        /*
index 203fa8eb8d6465e66d0e6b729c336f03a5e563d9..5ca70eab0f88ca81b7aa488f61ba1fbc249c79f3 100644 (file)
@@ -170,15 +170,19 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd,
                return CMD_SUCCESS;
        }
        ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
-
-       if (!vrf_name && ifp->vrf_id == VRF_DEFAULT)
-               vrf_name = VRF_DEFAULT_NAME;
-
-       if (ifp->vrf_id != VRF_DEFAULT) {
-               vrf = vrf_lookup_by_id(ifp->vrf_id);
-               if (vrf && !vrf_name)
-                       vrf_name = vrf->name;
+       if (!vrf_name) {
+               if (ifp) {
+                       if (ifp->vrf_id == VRF_DEFAULT)
+                               vrf_name = VRF_DEFAULT_NAME;
+                       else {
+                               vrf = vrf_lookup_by_id(ifp->vrf_id);
+                               if (vrf && !vrf_name)
+                                       vrf_name = vrf->name;
+                       }
+               } else
+                       vrf_name = VRF_DEFAULT_NAME;
        }
+
        area = isis_area_lookup_by_vrf(tag, vrf_name);
        if (!area) {
                isis_global_instance_create(vrf_name);
@@ -235,7 +239,7 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd,
        }
 
        /* check if the interface is a loopback and if so set it as passive */
-       if (if_is_loopback(ifp))
+       if (ifp && if_is_loopback(ifp))
                nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
                                      NB_OP_MODIFY, "true");
 
@@ -263,14 +267,19 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd,
                return CMD_SUCCESS;
 
        ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
-       if (!vrf_name && ifp->vrf_id == VRF_DEFAULT)
-               vrf_name = VRF_DEFAULT_NAME;
-
-       if (ifp->vrf_id != VRF_DEFAULT) {
-               vrf = vrf_lookup_by_id(ifp->vrf_id);
-               if (vrf && !vrf_name)
-                       vrf_name = vrf->name;
+       if (!vrf_name) {
+               if (ifp) {
+                       if (ifp->vrf_id == VRF_DEFAULT)
+                               vrf_name = VRF_DEFAULT_NAME;
+                       else {
+                               vrf = vrf_lookup_by_id(ifp->vrf_id);
+                               if (vrf && !vrf_name)
+                                       vrf_name = vrf->name;
+                       }
+               } else
+                       vrf_name = VRF_DEFAULT_NAME;
        }
+
        area = isis_area_lookup_by_vrf(tag, vrf_name);
        if (!area) {
                isis_global_instance_create(vrf_name);
@@ -326,7 +335,7 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd,
        }
 
        /* check if the interface is a loopback and if so set it as passive */
-       if (if_is_loopback(ifp))
+       if (ifp && if_is_loopback(ifp))
                nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
                                      NB_OP_MODIFY, "true");
 
@@ -1127,6 +1136,54 @@ void cli_show_isis_spf_ietf_backoff(struct vty *vty, struct lyd_node *dnode,
                yang_dnode_get_string(dnode, "./time-to-learn"));
 }
 
+/*
+ * XPath: /frr-isisd:isis/instance/spf/prefix-priorities/medium/access-list-name
+ */
+DEFPY_YANG(spf_prefix_priority, spf_prefix_priority_cmd,
+      "spf prefix-priority <critical|high|medium>$priority WORD$acl_name",
+      "SPF configuration\n"
+      "Configure a prefix priority list\n"
+      "Specify critical priority prefixes\n"
+      "Specify high priority prefixes\n"
+      "Specify medium priority prefixes\n"
+      "Access-list name\n")
+{
+       char xpath[XPATH_MAXLEN];
+
+       snprintf(xpath, XPATH_MAXLEN,
+                "./spf/prefix-priorities/%s/access-list-name", priority);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, acl_name);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG(no_spf_prefix_priority, no_spf_prefix_priority_cmd,
+      "no spf prefix-priority <critical|high|medium>$priority [WORD]",
+      NO_STR
+      "SPF configuration\n"
+      "Configure a prefix priority list\n"
+      "Specify critical priority prefixes\n"
+      "Specify high priority prefixes\n"
+      "Specify medium priority prefixes\n"
+      "Access-list name\n")
+{
+       char xpath[XPATH_MAXLEN];
+
+       snprintf(xpath, XPATH_MAXLEN,
+                "./spf/prefix-priorities/%s/access-list-name", priority);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_spf_prefix_priority(struct vty *vty, struct lyd_node *dnode,
+                                      bool show_defaults)
+{
+       vty_out(vty, " spf prefix-priority %s %s\n",
+               dnode->parent->schema->name,
+               yang_dnode_get_string(dnode, NULL));
+}
+
 /*
  * XPath: /frr-isisd:isis/instance/purge-originator
  */
@@ -1720,6 +1777,232 @@ void cli_show_isis_prefix_sid(struct vty *vty, struct lyd_node *dnode,
        vty_out(vty, "\n");
 }
 
+
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-{1,2}/lfa/priority-limit
+ */
+DEFPY_YANG (isis_frr_lfa_priority_limit,
+       isis_frr_lfa_priority_limit_cmd,
+       "[no] fast-reroute priority-limit <critical|high|medium>$priority [<level-1|level-2>$level]",
+       NO_STR
+       "Configure Fast ReRoute\n"
+       "Limit backup computation up to the prefix priority\n"
+       "Compute for critical priority prefixes only\n"
+       "Compute for critical & high priority prefixes\n"
+       "Compute for critical, high & medium priority prefixes\n"
+       "Set priority-limit for level-1 only\n"
+       "Set priority-limit for level-2 only\n")
+{
+       if (!level || strmatch(level, "level-1")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./fast-reroute/level-1/lfa/priority-limit",
+                               NB_OP_DESTROY, NULL);
+               } else {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./fast-reroute/level-1/lfa/priority-limit",
+                               NB_OP_CREATE, priority);
+               }
+       }
+       if (!level || strmatch(level, "level-2")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./fast-reroute/level-2/lfa/priority-limit",
+                               NB_OP_DESTROY, NULL);
+               } else {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./fast-reroute/level-2/lfa/priority-limit",
+                               NB_OP_CREATE, priority);
+               }
+       }
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_frr_lfa_priority_limit(struct vty *vty,
+                                         struct lyd_node *dnode,
+                                         bool show_defaults)
+{
+       vty_out(vty, " fast-reroute priority-limit %s %s\n",
+               yang_dnode_get_string(dnode, NULL),
+               dnode->parent->parent->schema->name);
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-{1,2}/lfa/tiebreaker
+ */
+DEFPY_YANG (isis_frr_lfa_tiebreaker,
+       isis_frr_lfa_tiebreaker_cmd,
+       "[no] fast-reroute lfa\
+          tiebreaker <downstream|lowest-backup-metric|node-protecting>$type\
+         index (1-255)$index\
+         [<level-1|level-2>$level]",
+       NO_STR
+       "Configure Fast ReRoute\n"
+       "LFA configuration\n"
+       "Configure tiebreaker for multiple backups\n"
+       "Prefer backup path via downstream node\n"
+       "Prefer backup path with lowest total metric\n"
+       "Prefer node protecting backup path\n"
+       "Set preference order among tiebreakers\n"
+       "Index\n"
+       "Configure tiebreaker for level-1 only\n"
+       "Configure tiebreaker for level-2 only\n")
+{
+       char xpath[XPATH_MAXLEN];
+
+       if (!level || strmatch(level, "level-1")) {
+               if (no) {
+                       snprintf(
+                               xpath, XPATH_MAXLEN,
+                               "./fast-reroute/level-1/lfa/tiebreaker[index='%s']",
+                               index_str);
+                       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+               } else {
+                       snprintf(
+                               xpath, XPATH_MAXLEN,
+                               "./fast-reroute/level-1/lfa/tiebreaker[index='%s']/type",
+                               index_str);
+                       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, type);
+               }
+       }
+       if (!level || strmatch(level, "level-2")) {
+               if (no) {
+                       snprintf(
+                               xpath, XPATH_MAXLEN,
+                               "./fast-reroute/level-2/lfa/tiebreaker[index='%s']",
+                               index_str);
+                       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+               } else {
+                       snprintf(
+                               xpath, XPATH_MAXLEN,
+                               "./fast-reroute/level-2/lfa/tiebreaker[index='%s']/type",
+                               index_str);
+                       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, type);
+               }
+       }
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_frr_lfa_tiebreaker(struct vty *vty, struct lyd_node *dnode,
+                                     bool show_defaults)
+{
+       vty_out(vty, " fast-reroute lfa tiebreaker %s index %s %s\n",
+               yang_dnode_get_string(dnode, "./type"),
+               yang_dnode_get_string(dnode, "./index"),
+               dnode->parent->parent->schema->name);
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-{1,2}/lfa/load-sharing
+ */
+DEFPY_YANG (isis_frr_lfa_load_sharing,
+       isis_frr_lfa_load_sharing_cmd,
+       "[no] fast-reroute load-sharing disable [<level-1|level-2>$level]",
+       NO_STR
+       "Configure Fast ReRoute\n"
+       "Load share prefixes across multiple backups\n"
+       "Disable load sharing\n"
+       "Disable load sharing for level-1 only\n"
+       "Disable load sharing for level-2 only\n")
+{
+       if (!level || strmatch(level, "level-1")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty, "./fast-reroute/level-1/lfa/load-sharing",
+                               NB_OP_MODIFY, "true");
+               } else {
+                       nb_cli_enqueue_change(
+                               vty, "./fast-reroute/level-1/lfa/load-sharing",
+                               NB_OP_MODIFY, "false");
+               }
+       }
+       if (!level || strmatch(level, "level-2")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty, "./fast-reroute/level-2/lfa/load-sharing",
+                               NB_OP_MODIFY, "true");
+               } else {
+                       nb_cli_enqueue_change(
+                               vty, "./fast-reroute/level-2/lfa/load-sharing",
+                               NB_OP_MODIFY, "false");
+               }
+       }
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_frr_lfa_load_sharing(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults)
+{
+       if (!yang_dnode_get_bool(dnode, NULL))
+               vty_out(vty, " no");
+
+       vty_out(vty, " fast-reroute load-sharing disable %s\n",
+               dnode->parent->parent->schema->name);
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-{1,2}/remote-lfa/prefix-list
+ */
+DEFPY_YANG (isis_frr_remote_lfa_plist,
+       isis_frr_remote_lfa_plist_cmd,
+       "fast-reroute remote-lfa prefix-list WORD$plist [<level-1|level-2>$level]",
+       "Configure Fast ReRoute\n"
+       "Enable remote LFA related configuration\n"
+       "Filter PQ node router ID based on prefix list\n"
+       "Prefix-list name\n"
+       "Enable router ID filtering for level-1 only\n"
+       "Enable router ID filtering for level-2 only\n")
+{
+       if (!level || strmatch(level, "level-1"))
+               nb_cli_enqueue_change(
+                       vty, "./fast-reroute/level-1/remote-lfa/prefix-list",
+                       NB_OP_MODIFY, plist);
+       if (!level || strmatch(level, "level-2"))
+               nb_cli_enqueue_change(
+                       vty, "./fast-reroute/level-2/remote-lfa/prefix-list",
+                       NB_OP_MODIFY, plist);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG (no_isis_frr_remote_lfa_plist,
+       no_isis_frr_remote_lfa_plist_cmd,
+       "no fast-reroute remote-lfa prefix-list [WORD] [<level-1|level-2>$level]",
+       NO_STR
+       "Configure Fast ReRoute\n"
+       "Enable remote LFA related configuration\n"
+       "Filter PQ node router ID based on prefix list\n"
+       "Prefix-list name\n"
+       "Enable router ID filtering for level-1 only\n"
+       "Enable router ID filtering for level-2 only\n")
+{
+       if (!level || strmatch(level, "level-1"))
+               nb_cli_enqueue_change(
+                       vty, "./fast-reroute/level-1/remote-lfa/prefix-list",
+                       NB_OP_DESTROY, NULL);
+       if (!level || strmatch(level, "level-2"))
+               nb_cli_enqueue_change(
+                       vty, "./fast-reroute/level-2/remote-lfa/prefix-list",
+                       NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_frr_remote_lfa_plist(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults)
+{
+       vty_out(vty, " fast-reroute remote-lfa prefix-list %s %s\n",
+               yang_dnode_get_string(dnode, NULL),
+               dnode->parent->parent->schema->name);
+}
+
 /*
  * XPath: /frr-interface:lib/interface/frr-isisd:isis/passive
  */
@@ -2377,7 +2660,281 @@ void cli_show_ip_isis_priority(struct vty *vty, struct lyd_node *dnode,
 }
 
 /*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/ti-lfa/enable
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/fast-reroute
+ */
+void cli_show_ip_isis_frr(struct vty *vty, struct lyd_node *dnode,
+                         bool show_defaults)
+{
+       bool l1_enabled, l2_enabled;
+       bool l1_node_protection, l2_node_protection;
+
+       /* Classic LFA */
+       l1_enabled = yang_dnode_get_bool(dnode, "./level-1/lfa/enable");
+       l2_enabled = yang_dnode_get_bool(dnode, "./level-2/lfa/enable");
+
+       if (l1_enabled || l2_enabled) {
+               if (l1_enabled == l2_enabled) {
+                       vty_out(vty, " isis fast-reroute lfa\n");
+                       vty_out(vty, "\n");
+               } else {
+                       if (l1_enabled)
+                               vty_out(vty,
+                                       " isis fast-reroute lfa level-1\n");
+                       if (l2_enabled)
+                               vty_out(vty,
+                                       " isis fast-reroute lfa level-2\n");
+               }
+       }
+
+       /* Remote LFA */
+       l1_enabled = yang_dnode_get_bool(dnode, "./level-1/remote-lfa/enable");
+       l2_enabled = yang_dnode_get_bool(dnode, "./level-2/remote-lfa/enable");
+
+       if (l1_enabled || l2_enabled) {
+               if (l1_enabled == l2_enabled) {
+                       vty_out(vty,
+                               " isis fast-reroute remote-lfa tunnel mpls-ldp\n");
+                       vty_out(vty, "\n");
+               } else {
+                       if (l1_enabled)
+                               vty_out(vty,
+                                       " isis fast-reroute remote-lfa tunnel mpls-ldp level-1\n");
+                       if (l2_enabled)
+                               vty_out(vty,
+                                       " isis fast-reroute remote-lfa tunnel mpls-ldp level-2\n");
+               }
+       }
+
+       /* TI-LFA */
+       l1_enabled = yang_dnode_get_bool(dnode, "./level-1/ti-lfa/enable");
+       l2_enabled = yang_dnode_get_bool(dnode, "./level-2/ti-lfa/enable");
+       l1_node_protection =
+               yang_dnode_get_bool(dnode, "./level-1/ti-lfa/node-protection");
+       l2_node_protection =
+               yang_dnode_get_bool(dnode, "./level-2/ti-lfa/node-protection");
+
+       if (l1_enabled || l2_enabled) {
+               if (l1_enabled == l2_enabled
+                   && l1_node_protection == l2_node_protection) {
+                       vty_out(vty, " isis fast-reroute ti-lfa");
+                       if (l1_node_protection)
+                               vty_out(vty, " node-protection");
+                       vty_out(vty, "\n");
+               } else {
+                       if (l1_enabled) {
+                               vty_out(vty,
+                                       " isis fast-reroute ti-lfa level-1");
+                               if (l1_node_protection)
+                                       vty_out(vty, " node-protection");
+                               vty_out(vty, "\n");
+                       }
+                       if (l2_enabled) {
+                               vty_out(vty,
+                                       " isis fast-reroute ti-lfa level-2");
+                               if (l2_node_protection)
+                                       vty_out(vty, " node-protection");
+                               vty_out(vty, "\n");
+                       }
+               }
+       }
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-{1,2}/lfa/enable
+ */
+DEFPY(isis_lfa, isis_lfa_cmd,
+      "[no] isis fast-reroute lfa [level-1|level-2]$level",
+      NO_STR
+      "IS-IS routing protocol\n"
+      "Interface IP Fast-reroute configuration\n"
+      "Enable LFA computation\n"
+      "Enable LFA computation for Level 1 only\n"
+      "Enable LFA computation for Level 2 only\n")
+{
+       if (!level || strmatch(level, "level-1")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-1/lfa/enable",
+                               NB_OP_MODIFY, "false");
+               } else {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-1/lfa/enable",
+                               NB_OP_MODIFY, "true");
+               }
+       }
+       if (!level || strmatch(level, "level-2")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-2/lfa/enable",
+                               NB_OP_MODIFY, "false");
+               } else {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-2/lfa/enable",
+                               NB_OP_MODIFY, "true");
+               }
+       }
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-{1,2}/lfa/exclude-interface
+ */
+DEFPY(isis_lfa_exclude_interface, isis_lfa_exclude_interface_cmd,
+      "[no] isis fast-reroute lfa [level-1|level-2]$level exclude interface IFNAME$ifname",
+      NO_STR
+      "IS-IS routing protocol\n"
+      "Interface IP Fast-reroute configuration\n"
+      "Enable LFA computation\n"
+      "Enable LFA computation for Level 1 only\n"
+      "Enable LFA computation for Level 2 only\n"
+      "FRR exclusion information\n"
+      "Exclude an interface from computation\n"
+      "Interface name\n")
+{
+       if (!level || strmatch(level, "level-1")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-1/lfa/exclude-interface",
+                               NB_OP_DESTROY, ifname);
+               } else {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-1/lfa/exclude-interface",
+                               NB_OP_CREATE, ifname);
+               }
+       }
+       if (!level || strmatch(level, "level-2")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-2/lfa/exclude-interface",
+                               NB_OP_DESTROY, ifname);
+               } else {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-2/lfa/exclude-interface",
+                               NB_OP_CREATE, ifname);
+               }
+       }
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_frr_lfa_exclude_interface(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults)
+{
+       vty_out(vty, " isis fast-reroute lfa %s exclude interface %s\n",
+               dnode->parent->parent->schema->name,
+               yang_dnode_get_string(dnode, NULL));
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-{1,2}/remote-lfa/enable
+ */
+DEFPY(isis_remote_lfa, isis_remote_lfa_cmd,
+      "[no] isis fast-reroute remote-lfa tunnel mpls-ldp [level-1|level-2]$level",
+      NO_STR
+      "IS-IS routing protocol\n"
+      "Interface IP Fast-reroute configuration\n"
+      "Enable remote LFA computation\n"
+      "Enable remote LFA computation using tunnels\n"
+      "Use MPLS LDP tunnel to reach the remote LFA node\n"
+      "Enable LFA computation for Level 1 only\n"
+      "Enable LFA computation for Level 2 only\n")
+{
+       if (!level || strmatch(level, "level-1")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-1/remote-lfa/enable",
+                               NB_OP_MODIFY, "false");
+               } else {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-1/remote-lfa/enable",
+                               NB_OP_MODIFY, "true");
+               }
+       }
+       if (!level || strmatch(level, "level-2")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-2/remote-lfa/enable",
+                               NB_OP_MODIFY, "false");
+               } else {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-2/remote-lfa/enable",
+                               NB_OP_MODIFY, "true");
+               }
+       }
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-{1,2}/remote-lfa/maximum-metric
+ */
+DEFPY(isis_remote_lfa_max_metric, isis_remote_lfa_max_metric_cmd,
+      "[no] isis fast-reroute remote-lfa maximum-metric (1-16777215)$metric [level-1|level-2]$level",
+      NO_STR
+      "IS-IS routing protocol\n"
+      "Interface IP Fast-reroute configuration\n"
+      "Enable remote LFA computation\n"
+      "Limit remote LFA node selection within the metric\n"
+      "Value of the metric\n"
+      "Enable LFA computation for Level 1 only\n"
+      "Enable LFA computation for Level 2 only\n")
+{
+       if (!level || strmatch(level, "level-1")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-1/remote-lfa/maximum-metric",
+                               NB_OP_DESTROY, NULL);
+               } else {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-1/remote-lfa/maximum-metric",
+                               NB_OP_MODIFY, metric_str);
+               }
+       }
+       if (!level || strmatch(level, "level-2")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-2/remote-lfa/maximum-metric",
+                               NB_OP_DESTROY, NULL);
+               } else {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-2/remote-lfa/maximum-metric",
+                               NB_OP_MODIFY, metric_str);
+               }
+       }
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_frr_remote_lfa_max_metric(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults)
+{
+       vty_out(vty, " isis fast-reroute remote-lfa maximum-metric %s %s\n",
+               yang_dnode_get_string(dnode, NULL),
+               dnode->parent->parent->schema->name);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-{1,2}/ti-lfa/enable
  */
 DEFPY(isis_ti_lfa, isis_ti_lfa_cmd,
       "[no] isis fast-reroute ti-lfa [level-1|level-2]$level [node-protection$node_protection]",
@@ -2437,41 +2994,6 @@ DEFPY(isis_ti_lfa, isis_ti_lfa_cmd,
        return nb_cli_apply_changes(vty, NULL);
 }
 
-void cli_show_ip_isis_ti_lfa(struct vty *vty, struct lyd_node *dnode,
-                            bool show_defaults)
-{
-       bool l1_enabled, l2_enabled;
-       bool l1_node_protection, l2_node_protection;
-
-       l1_enabled = yang_dnode_get_bool(dnode, "./level-1/ti-lfa/enable");
-       l2_enabled = yang_dnode_get_bool(dnode, "./level-2/ti-lfa/enable");
-       l1_node_protection =
-               yang_dnode_get_bool(dnode, "./level-1/ti-lfa/node-protection");
-       l2_node_protection =
-               yang_dnode_get_bool(dnode, "./level-2/ti-lfa/node-protection");
-
-       if (l1_enabled == l2_enabled
-           && l1_node_protection == l2_node_protection) {
-               vty_out(vty, " isis fast-reroute ti-lfa");
-               if (l1_node_protection)
-                       vty_out(vty, " node-protection");
-               vty_out(vty, "\n");
-       } else {
-               if (l1_enabled) {
-                       vty_out(vty, " isis fast-reroute ti-lfa level-1");
-                       if (l1_node_protection)
-                               vty_out(vty, " node-protection");
-                       vty_out(vty, "\n");
-               }
-               if (l2_enabled) {
-                       vty_out(vty, " isis fast-reroute ti-lfa level-2");
-                       if (l2_node_protection)
-                               vty_out(vty, " node-protection");
-                       vty_out(vty, "\n");
-               }
-       }
-}
-
 /*
  * XPath: /frr-isisd:isis/instance/log-adjacency-changes
  */
@@ -2705,6 +3227,8 @@ void isis_cli_init(void)
 
        install_element(ISIS_NODE, &spf_interval_cmd);
        install_element(ISIS_NODE, &no_spf_interval_cmd);
+       install_element(ISIS_NODE, &spf_prefix_priority_cmd);
+       install_element(ISIS_NODE, &no_spf_prefix_priority_cmd);
        install_element(ISIS_NODE, &spf_delay_ietf_cmd);
        install_element(ISIS_NODE, &no_spf_delay_ietf_cmd);
 
@@ -2731,6 +3255,11 @@ void isis_cli_init(void)
        install_element(ISIS_NODE, &no_isis_sr_node_msd_cmd);
        install_element(ISIS_NODE, &isis_sr_prefix_sid_cmd);
        install_element(ISIS_NODE, &no_isis_sr_prefix_sid_cmd);
+       install_element(ISIS_NODE, &isis_frr_lfa_priority_limit_cmd);
+       install_element(ISIS_NODE, &isis_frr_lfa_tiebreaker_cmd);
+       install_element(ISIS_NODE, &isis_frr_lfa_load_sharing_cmd);
+       install_element(ISIS_NODE, &isis_frr_remote_lfa_plist_cmd);
+       install_element(ISIS_NODE, &no_isis_frr_remote_lfa_plist_cmd);
 
        install_element(INTERFACE_NODE, &isis_passive_cmd);
 
@@ -2766,6 +3295,10 @@ void isis_cli_init(void)
        install_element(INTERFACE_NODE, &isis_priority_cmd);
        install_element(INTERFACE_NODE, &no_isis_priority_cmd);
 
+       install_element(INTERFACE_NODE, &isis_lfa_cmd);
+       install_element(INTERFACE_NODE, &isis_lfa_exclude_interface_cmd);
+       install_element(INTERFACE_NODE, &isis_remote_lfa_cmd);
+       install_element(INTERFACE_NODE, &isis_remote_lfa_max_metric_cmd);
        install_element(INTERFACE_NODE, &isis_ti_lfa_cmd);
 
        install_element(ISIS_NODE, &log_adj_changes_cmd);
index 988af64c488d779c276b0486a99f17a545215b00..00bef5c7829583f0d6214fc6b31f699718dcbdf5 100644 (file)
@@ -122,7 +122,6 @@ int isis_ldp_sync_announce_update(struct ldp_igp_sync_announce announce)
        /* LDP just started up:
         *  set cost to LSInfinity
         *  send request to LDP for LDP-SYNC state for each interface
-        *  start hello timer
         */
        vrf = vrf_lookup_by_id(VRF_DEFAULT);
        FOR_ALL_INTERFACES (vrf, ifp) {
@@ -135,62 +134,6 @@ int isis_ldp_sync_announce_update(struct ldp_igp_sync_announce announce)
                }
        }
 
-       THREAD_OFF(isis->ldp_sync_cmd.t_hello);
-
-       isis->ldp_sync_cmd.sequence = 0;
-       isis_ldp_sync_hello_timer_add();
-
-       return 0;
-}
-
-int isis_ldp_sync_hello_update(struct ldp_igp_sync_hello hello)
-{
-       struct isis_area *area;
-       struct listnode *node;
-       struct vrf *vrf;
-       struct interface *ifp;
-       struct isis_circuit *circuit;
-       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
-
-       /* if isis is not enabled or LDP-SYNC is not configured ignore */
-       if (!isis ||
-           !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
-               return 0;
-
-       if (hello.proto != ZEBRA_ROUTE_LDP)
-               return 0;
-
-       /* Received Hello from LDP:
-        *  if current sequence number is greater than received hello
-        *  sequence number then assume LDP restarted
-        *  set cost to LSInfinity
-        *  send request to LDP for LDP-SYNC state for each interface
-        *  else all is fine just restart hello timer
-        */
-       if (hello.sequence == 0)
-               /* rolled over */
-               isis->ldp_sync_cmd.sequence = 0;
-
-       if (isis->ldp_sync_cmd.sequence > hello.sequence) {
-               zlog_err("ldp_sync: LDP restarted");
-
-               vrf = vrf_lookup_by_id(VRF_DEFAULT);
-               FOR_ALL_INTERFACES (vrf, ifp) {
-                       for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
-                                                 area)) {
-                               circuit = circuit_lookup_by_ifp(ifp,
-                                       area->circuit_list);
-                               if (circuit == NULL)
-                                       continue;
-                               isis_ldp_sync_if_start(circuit, true);
-                       }
-               }
-       } else {
-               THREAD_OFF(isis->ldp_sync_cmd.t_hello);
-               isis_ldp_sync_hello_timer_add();
-       }
-       isis->ldp_sync_cmd.sequence = hello.sequence;
-
        return 0;
 }
 
@@ -293,7 +236,7 @@ void isis_ldp_sync_ldp_fail(struct isis_circuit *circuit)
 
        ldp_sync_info = circuit->ldp_sync_info;
 
-       /* LDP failed to send hello:
+       /* LDP client close detected:
         *  stop holddown timer
         *  set cost of interface to LSInfinity so traffic will use different
         *  interface until LDP restarts and has learned all labels from peer
@@ -429,20 +372,24 @@ void isis_ldp_sync_set_if_metric(struct isis_circuit *circuit, bool run_regen)
                        if (circuit->area->newmetric) {
                                ldp_sync_info->metric[0] =
                                        circuit->te_metric[0];
-                               circuit->te_metric[0] = LDP_ISIS_LSINFINITY;
+                               circuit->te_metric[0] =
+                                       ISIS_WIDE_METRIC_INFINITY;
                        } else {
                                ldp_sync_info->metric[0] = circuit->metric[0];
-                               circuit->metric[0] = LDP_ISIS_LSINFINITY_NL;
+                               circuit->metric[0] =
+                                       ISIS_NARROW_METRIC_INFINITY;
                        }
                }
                if (circuit->is_type & IS_LEVEL_2) {
                        if (circuit->area->newmetric) {
                                ldp_sync_info->metric[1] =
                                        circuit->te_metric[1];
-                               circuit->te_metric[1] = LDP_ISIS_LSINFINITY;
+                               circuit->te_metric[1] =
+                                       ISIS_WIDE_METRIC_INFINITY;
                        } else {
                                ldp_sync_info->metric[1] = circuit->metric[1];
-                               circuit->metric[1] = LDP_ISIS_LSINFINITY_NL;
+                               circuit->metric[1] =
+                                       ISIS_NARROW_METRIC_INFINITY;
                        }
                }
        } else {
@@ -518,9 +465,9 @@ void isis_ldp_sync_holddown_timer_add(struct isis_circuit *circuit)
 }
 
 /*
- * LDP-SYNC hello timer routines
+ * LDP-SYNC handle client close routine
  */
-static int isis_ldp_sync_hello_timer(struct thread *thread)
+void isis_ldp_sync_handle_client_close(struct zapi_client_close_info *info)
 {
        struct isis_area *area;
        struct listnode *node;
@@ -529,44 +476,30 @@ static int isis_ldp_sync_hello_timer(struct thread *thread)
        struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
        struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
 
-       if (!isis)
-               return 0;
+       /* if isis is not enabled or LDP-SYNC is not configured ignore */
+       if (!isis
+           || !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+               return;
+
+       /* Check if the LDP main client session closed */
+       if (info->proto != ZEBRA_ROUTE_LDP || info->session_id == 0)
+               return;
 
-       /* hello timer expired:
-        *  didn't receive hello msg from LDP
-        *  set cost of all interfaces to LSInfinity
+       /* Handle the zebra notification that the LDP client session closed.
+        *  set cost to LSInfinity
+        *  send request to LDP for LDP-SYNC state for each interface
         */
+       zlog_err("ldp_sync: LDP down");
+
        FOR_ALL_INTERFACES (vrf, ifp) {
                for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
-                       circuit = circuit_lookup_by_ifp(ifp,
-                                                       area->circuit_list);
+                       circuit =
+                               circuit_lookup_by_ifp(ifp, area->circuit_list);
                        if (circuit == NULL)
                                continue;
-
                        isis_ldp_sync_ldp_fail(circuit);
                }
        }
-
-       zlog_debug("ldp_sync: hello timer expired, LDP down");
-
-       return 0;
-}
-
-void isis_ldp_sync_hello_timer_add(void)
-{
-       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
-
-       /* Start hello timer:
-        *  this timer is used to make sure LDP is up
-        *  if expires set interface cost to LSInfinity
-        */
-       if (!isis ||
-           !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
-               return;
-
-       thread_add_timer(master, isis_ldp_sync_hello_timer,
-                        NULL, LDP_IGP_SYNC_HELLO_TIMEOUT,
-                        &isis->ldp_sync_cmd.t_hello);
 }
 
 /*
@@ -657,13 +590,11 @@ void isis_ldp_sync_gbl_exit(bool remove)
                                          LDP_IGP_SYNC_IF_STATE_UPDATE);
                zclient_unregister_opaque(zclient,
                                          LDP_IGP_SYNC_ANNOUNCE_UPDATE);
-               zclient_unregister_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE);
 
                /* disable LDP-SYNC globally */
                UNSET_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
                UNSET_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
                isis->ldp_sync_cmd.holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
-               THREAD_OFF(isis->ldp_sync_cmd.t_hello);
 
                /* remove LDP-SYNC on all ISIS interfaces */
                FOR_ALL_INTERFACES (vrf, ifp) {
index 6017cdf001863cc501fea66c5e682a2f738aa17f..977c5ba0defd689ab3d2a3fd11f33ea029ca2d1a 100644 (file)
@@ -20,8 +20,7 @@
 #ifndef _ZEBRA_ISIS_LDP_SYNC_H
 #define _ZEBRA_ISIS_LDP_SYNC_H
 
-#define LDP_ISIS_LSINFINITY 0xFFFFFE  /* wide link metric */
-#define LDP_ISIS_LSINFINITY_NL 62     /* narrow link metric */
+#include "zclient.h"
 
 /* Macro to log debug message */
 #define ils_debug(...)                                                         \
@@ -39,11 +38,11 @@ extern void isis_ldp_sync_if_start(struct isis_circuit *circuit,
 extern void isis_ldp_sync_if_remove(struct isis_circuit *circuit, bool remove);
 extern void isis_ldp_sync_if_complete(struct isis_circuit *circuit);
 extern void isis_ldp_sync_holddown_timer_add(struct isis_circuit *circuit);
-extern void isis_ldp_sync_hello_timer_add(void);
+extern void
+isis_ldp_sync_handle_client_close(struct zapi_client_close_info *info);
 extern void isis_ldp_sync_ldp_fail(struct isis_circuit *circuit);
 extern int isis_ldp_sync_state_update(struct ldp_igp_sync_if_state state);
 extern int isis_ldp_sync_announce_update(struct ldp_igp_sync_announce announce);
-extern int isis_ldp_sync_hello_update(struct ldp_igp_sync_hello hello);
 extern void isis_ldp_sync_state_req_msg(struct isis_circuit *circuit);
 extern void isis_ldp_sync_set_if_metric(struct isis_circuit *circuit,
                                        bool run_regen);
index f22e4a708555d9f78c66cf857110291bedfb584f..5b3a3827a24cf28412e5a5abf1b19bc965d5bf57 100644 (file)
@@ -25,6 +25,8 @@
 #include "vrf.h"
 #include "table.h"
 #include "srcdest_table.h"
+#include "plist.h"
+#include "zclient.h"
 
 #include "isis_common.h"
 #include "isisd.h"
 #include "isis_mt.h"
 #include "isis_tlvs.h"
 #include "isis_spf_private.h"
-#include "isisd/isis_errors.h"
+#include "isis_zebra.h"
+#include "isis_errors.h"
 
 DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_NODE, "ISIS SPF Node");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_LFA_TIEBREAKER, "ISIS LFA Tiebreaker");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_LFA_EXCL_IFACE, "ISIS LFA Excluded Interface");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_RLFA, "ISIS Remote LFA");
 
 static inline int isis_spf_node_compare(const struct isis_spf_node *a,
                                        const struct isis_spf_node *b)
@@ -119,6 +125,185 @@ struct isis_spf_node *isis_spf_node_find(const struct isis_spf_nodes *nodes,
        return RB_FIND(isis_spf_nodes, nodes, &node);
 }
 
+/**
+ * LFA tiebreaker RB-tree comparison function.
+ *
+ * @param a    First LFA tiebreaker
+ * @param b    Second LFA tiebreaker
+ *
+ * @return     -1 (a < b), 0 (a == b) or +1 (a > b)
+ */
+int lfa_tiebreaker_cmp(const struct lfa_tiebreaker *a,
+                      const struct lfa_tiebreaker *b)
+{
+       if (a->index < b->index)
+               return -1;
+       if (a->index > b->index)
+               return 1;
+
+       return a->type - b->type;
+}
+
+/**
+ * Initialize list of LFA tie-breakers.
+ *
+ * @param area         IS-IS area
+ * @param level                IS-IS level
+ */
+void isis_lfa_tiebreakers_init(struct isis_area *area, int level)
+{
+       lfa_tiebreaker_tree_init(&area->lfa_tiebreakers[level - 1]);
+}
+
+/**
+ * Clear list of LFA tie-breakers, releasing all allocated memory.
+ *
+ * @param area         IS-IS area
+ * @param level                IS-IS level
+ */
+void isis_lfa_tiebreakers_clear(struct isis_area *area, int level)
+{
+       while (lfa_tiebreaker_tree_count(&area->lfa_tiebreakers[level - 1])
+              > 0) {
+               struct lfa_tiebreaker *tie_b;
+
+               tie_b = lfa_tiebreaker_tree_first(
+                       &area->lfa_tiebreakers[level - 1]);
+               isis_lfa_tiebreaker_delete(area, level, tie_b);
+       }
+}
+
+/**
+ * Add new LFA tie-breaker to list of LFA tie-breakers.
+ *
+ * @param area         IS-IS area
+ * @param level                IS-IS level
+ * @param index                LFA tie-breaker index
+ * @param type         LFA tie-breaker type
+ *
+ * @return             Pointer to new LFA tie-breaker structure.
+ */
+struct lfa_tiebreaker *isis_lfa_tiebreaker_add(struct isis_area *area,
+                                              int level, uint8_t index,
+                                              enum lfa_tiebreaker_type type)
+{
+       struct lfa_tiebreaker *tie_b;
+
+       tie_b = XCALLOC(MTYPE_ISIS_LFA_TIEBREAKER, sizeof(*tie_b));
+       tie_b->index = index;
+       tie_b->type = type;
+       tie_b->area = area;
+       lfa_tiebreaker_tree_add(&area->lfa_tiebreakers[level - 1], tie_b);
+
+       return tie_b;
+}
+
+/**
+ * Remove LFA tie-breaker from list of LFA tie-breakers.
+ *
+ * @param area         IS-IS area
+ * @param level                IS-IS level
+ * @param tie_b                Pointer to LFA tie-breaker structure
+ */
+void isis_lfa_tiebreaker_delete(struct isis_area *area, int level,
+                               struct lfa_tiebreaker *tie_b)
+{
+       lfa_tiebreaker_tree_del(&area->lfa_tiebreakers[level - 1], tie_b);
+       XFREE(MTYPE_ISIS_LFA_TIEBREAKER, tie_b);
+}
+
+static bool lfa_excl_interface_hash_cmp(const void *value1, const void *value2)
+{
+       return strmatch(value1, value2);
+}
+
+static unsigned int lfa_excl_interface_hash_make(const void *value)
+{
+       return string_hash_make(value);
+}
+
+static void *lfa_excl_interface_hash_alloc(void *p)
+{
+       return XSTRDUP(MTYPE_ISIS_LFA_EXCL_IFACE, p);
+}
+
+static void lfa_excl_interface_hash_free(void *arg)
+{
+       XFREE(MTYPE_ISIS_LFA_EXCL_IFACE, arg);
+}
+
+/**
+ * Initialize hash table of LFA excluded interfaces.
+ *
+ * @param circuit      IS-IS interface
+ * @param level                IS-IS level
+ */
+void isis_lfa_excluded_ifaces_init(struct isis_circuit *circuit, int level)
+{
+       circuit->lfa_excluded_ifaces[level - 1] = hash_create(
+               lfa_excl_interface_hash_make, lfa_excl_interface_hash_cmp,
+               "LFA Excluded Interfaces");
+}
+
+/**
+ * Clear hash table of LFA excluded interfaces, releasing all allocated memory.
+ *
+ * @param nodes                List of SPF nodes
+ */
+void isis_lfa_excluded_ifaces_clear(struct isis_circuit *circuit, int level)
+{
+       hash_clean(circuit->lfa_excluded_ifaces[level - 1],
+                  lfa_excl_interface_hash_free);
+}
+
+/**
+ * Add new interface to hash table of excluded interfaces.
+ *
+ * @param circuit      IS-IS interface
+ * @param level                IS-IS level
+ * @param ifname       Excluded interface name
+ */
+void isis_lfa_excluded_iface_add(struct isis_circuit *circuit, int level,
+                                const char *ifname)
+{
+       hash_get(circuit->lfa_excluded_ifaces[level - 1], (char *)ifname,
+                lfa_excl_interface_hash_alloc);
+}
+
+/**
+ * Remove interface from hash table of excluded interfaces.
+ *
+ * @param circuit      IS-IS interface
+ * @param level                IS-IS level
+ * @param ifname       Excluded interface name
+ */
+void isis_lfa_excluded_iface_delete(struct isis_circuit *circuit, int level,
+                                   const char *ifname)
+{
+       char *found;
+
+       found = hash_lookup(circuit->lfa_excluded_ifaces[level - 1],
+                           (char *)ifname);
+       if (found) {
+               hash_release(circuit->lfa_excluded_ifaces[level - 1], found);
+               lfa_excl_interface_hash_free(found);
+       }
+}
+
+/**
+ * Lookup excluded interface.
+ *
+ * @param circuit      IS-IS interface
+ * @param level                IS-IS level
+ * @param ifname       Excluded interface name
+ */
+bool isis_lfa_excluded_iface_check(struct isis_circuit *circuit, int level,
+                                  const char *ifname)
+{
+       return hash_lookup(circuit->lfa_excluded_ifaces[level - 1],
+                          (char *)ifname);
+}
+
 /**
  * Check if a given IS-IS adjacency needs to be excised when computing the SPF
  * post-convergence tree.
@@ -135,7 +320,7 @@ bool isis_lfa_excise_adj_check(const struct isis_spftree *spftree,
 {
        const struct lfa_protected_resource *resource;
 
-       if (spftree->type != SPF_TYPE_TI_LFA)
+       if (spftree->type != SPF_TYPE_RLFA && spftree->type != SPF_TYPE_TI_LFA)
                return false;
 
        /*
@@ -438,10 +623,10 @@ static int tilfa_build_repair_list(struct isis_spftree *spftree_pc,
        uint32_t sid_index;
        mpls_label_t label_qnode;
 
-       if (IS_DEBUG_TILFA) {
+       if (IS_DEBUG_LFA) {
                vid2string(vertex, buf, sizeof(buf));
-               zlog_debug("ISIS-TI-LFA: vertex %s %s",
-                          vtype2string(vertex->type), buf);
+               zlog_debug("ISIS-LFA: vertex %s %s", vtype2string(vertex->type),
+                          buf);
        }
 
        /* Push original Prefix-SID label when necessary. */
@@ -450,9 +635,9 @@ static int tilfa_build_repair_list(struct isis_spftree *spftree_pc,
                assert(pvertex);
 
                sid_index = vertex->N.ip.sr.sid.value;
-               if (IS_DEBUG_TILFA)
+               if (IS_DEBUG_LFA)
                        zlog_debug(
-                               "ISIS-TI-LFA: pushing Prefix-SID to %pFX (index %u)",
+                               "ISIS-LFA: pushing Prefix-SID to %pFX (index %u)",
                                &vertex->N.ip.p.dest, sid_index);
                sid_dest.type = TILFA_SID_PREFIX;
                sid_dest.value.index.value = sid_index;
@@ -481,14 +666,14 @@ static int tilfa_build_repair_list(struct isis_spftree *spftree_pc,
                label_qnode = tilfa_find_qnode_adj_sid(spftree_pc, vertex->N.id,
                                                       vertex_child->N.id);
                if (label_qnode == MPLS_INVALID_LABEL) {
-                       zlog_warn("ISIS-TI-LFA: failed to find %s->%s Adj-SID",
+                       zlog_warn("ISIS-LFA: failed to find %s->%s Adj-SID",
                                  print_sys_hostname(vertex->N.id),
                                  print_sys_hostname(vertex_child->N.id));
                        return -1;
                }
-               if (IS_DEBUG_TILFA)
+               if (IS_DEBUG_LFA)
                        zlog_debug(
-                               "ISIS-TI-LFA: pushing %s->%s Adj-SID (label %u)",
+                               "ISIS-LFA: pushing %s->%s Adj-SID (label %u)",
                                print_sys_hostname(vertex->N.id),
                                print_sys_hostname(vertex_child->N.id),
                                label_qnode);
@@ -501,17 +686,17 @@ static int tilfa_build_repair_list(struct isis_spftree *spftree_pc,
        if (is_pnode) {
                /* The same P-node can't be used more than once. */
                if (isis_spf_node_find(used_pnodes, vertex->N.id)) {
-                       if (IS_DEBUG_TILFA)
+                       if (IS_DEBUG_LFA)
                                zlog_debug(
-                                       "ISIS-TI-LFA: skipping already used P-node");
+                                       "ISIS-LFA: skipping already used P-node");
                        return 0;
                }
                isis_spf_node_new(used_pnodes, vertex->N.id);
 
                if (!vertex_child) {
-                       if (IS_DEBUG_TILFA)
+                       if (IS_DEBUG_LFA)
                                zlog_debug(
-                                       "ISIS-TI-LFA: destination is within Ext-P-Space");
+                                       "ISIS-LFA: destination is within Ext-P-Space");
                        return 0;
                }
 
@@ -519,20 +704,29 @@ static int tilfa_build_repair_list(struct isis_spftree *spftree_pc,
                        tilfa_find_pnode_prefix_sid(spftree_pc, vertex->N.id);
                if (sid_index == UINT32_MAX) {
                        zlog_warn(
-                               "ISIS-TI-LFA: failed to find Prefix-SID corresponding to PQ-node %s",
+                               "ISIS-LFA: failed to find Prefix-SID corresponding to PQ-node %s",
                                print_sys_hostname(vertex->N.id));
                        return -1;
                }
 
-               if (IS_DEBUG_TILFA)
+               if (IS_DEBUG_LFA)
                        zlog_debug(
-                               "ISIS-TI-LFA: pushing Node-SID to %s (index %u)",
+                               "ISIS-LFA: pushing Node-SID to %s (index %u)",
                                print_sys_hostname(vertex->N.id), sid_index);
                sid_pnode.type = TILFA_SID_PREFIX;
                sid_pnode.value.index.value = sid_index;
                listnode_add_head(repair_list, &sid_pnode);
 
                /* Apply repair list. */
+               if (spftree_pc->area->srdb.config.msd
+                   && listcount(repair_list)
+                              > spftree_pc->area->srdb.config.msd) {
+                       zlog_warn(
+                               "ISIS-LFA: list of repair segments exceeds locally configured MSD (%u > %u)",
+                               listcount(repair_list),
+                               spftree_pc->area->srdb.config.msd);
+                       return -1;
+               }
                if (tilfa_repair_list_apply(spftree_pc, vertex_dest, vertex,
                                            repair_list)
                    != 0)
@@ -610,36 +804,25 @@ spf_adj_check_is_affected(const struct isis_spf_adj *sadj,
        return false;
 }
 
-/* Check if the given SPF vertex needs LFA protection. */
-static bool lfa_check_needs_protection(const struct isis_spftree *spftree_pc,
-                                      const struct isis_vertex *vertex)
+/* Check if the given vertex is affected by a given local failure. */
+static bool
+spf_vertex_check_is_affected(const struct isis_vertex *vertex,
+                            const uint8_t *root_sysid,
+                            const struct lfa_protected_resource *resource)
 {
-       struct isis_vertex *vertex_old;
+       struct isis_vertex_adj *vadj;
        struct listnode *node;
        size_t affected_nhs = 0;
-       struct isis_vertex_adj *vadj;
 
        /* Local routes don't need protection. */
        if (VTYPE_IP(vertex->type) && vertex->depth == 1)
                return false;
 
-       /* Only local adjacencies need Adj-SID protection. */
-       if (VTYPE_IS(vertex->type)
-           && !isis_adj_find(spftree_pc->area, spftree_pc->level,
-                             vertex->N.id))
-               return false;
-
-       vertex_old = isis_find_vertex(&spftree_pc->lfa.old.spftree->paths,
-                                     &vertex->N, vertex->type);
-       if (!vertex_old)
-               return false;
-
-       for (ALL_LIST_ELEMENTS_RO(vertex_old->Adj_N, node, vadj)) {
+       for (ALL_LIST_ELEMENTS_RO(vertex->Adj_N, node, vadj)) {
                struct isis_spf_adj *sadj = vadj->sadj;
 
-               if (spf_adj_check_is_affected(
-                           sadj, &spftree_pc->lfa.protected_resource,
-                           spftree_pc->sysid, false))
+               if (spf_adj_check_is_affected(sadj, resource, root_sysid,
+                                             false))
                        affected_nhs++;
        }
 
@@ -647,12 +830,38 @@ static bool lfa_check_needs_protection(const struct isis_spftree *spftree_pc,
         * No need to compute backup paths for ECMP routes, except if all
         * primary nexthops share the same broadcast interface.
         */
-       if (listcount(vertex_old->Adj_N) == affected_nhs)
+       if (listcount(vertex->Adj_N) == affected_nhs)
                return true;
 
        return false;
 }
 
+/* Check if a given RLFA/TI-LFA post-convergence SPF vertex needs protection. */
+static bool lfa_check_needs_protection(const struct isis_spftree *spftree_pc,
+                                      const struct isis_vertex *vertex)
+{
+       struct isis_vertex *vertex_old;
+
+       /* Only local adjacencies need TI-LFA Adj-SID protection. */
+       if (spftree_pc->type == SPF_TYPE_TI_LFA && VTYPE_IS(vertex->type)
+           && !isis_adj_find(spftree_pc->area, spftree_pc->level,
+                             vertex->N.id))
+               return false;
+
+       vertex_old = isis_find_vertex(&spftree_pc->lfa.old.spftree->paths,
+                                     &vertex->N, vertex->type);
+       if (!vertex_old)
+               return false;
+
+       /* Skip vertex if it's already protected by local LFA. */
+       if (CHECK_FLAG(vertex_old->flags, F_ISIS_VERTEX_LFA_PROTECTED))
+               return false;
+
+       return spf_vertex_check_is_affected(
+               vertex_old, spftree_pc->sysid,
+               &spftree_pc->lfa.protected_resource);
+}
+
 /**
  * Check if the given SPF vertex needs protection and, if so, compute and
  * install the corresponding repair paths.
@@ -662,7 +871,8 @@ static bool lfa_check_needs_protection(const struct isis_spftree *spftree_pc,
  *
  * @return             0 if the vertex needs to be protected, -1 otherwise
  */
-int isis_lfa_check(struct isis_spftree *spftree_pc, struct isis_vertex *vertex)
+int isis_tilfa_check(struct isis_spftree *spftree_pc,
+                    struct isis_vertex *vertex)
 {
        struct isis_spf_nodes used_pnodes;
        char buf[VID2STR_BUFFER];
@@ -672,14 +882,12 @@ int isis_lfa_check(struct isis_spftree *spftree_pc, struct isis_vertex *vertex)
        if (!spftree_pc->area->srdb.enabled)
                return -1;
 
-       if (IS_DEBUG_TILFA)
-               vid2string(vertex, buf, sizeof(buf));
-
        if (!lfa_check_needs_protection(spftree_pc, vertex)) {
-               if (IS_DEBUG_TILFA)
+               if (IS_DEBUG_LFA)
                        zlog_debug(
-                               "ISIS-TI-LFA: %s %s unaffected by %s",
-                               vtype2string(vertex->type), buf,
+                               "ISIS-LFA: %s %s unaffected by %s",
+                               vtype2string(vertex->type),
+                               vid2string(vertex, buf, sizeof(buf)),
                                lfa_protected_resource2str(
                                        &spftree_pc->lfa.protected_resource));
 
@@ -697,10 +905,11 @@ int isis_lfa_check(struct isis_spftree *spftree_pc, struct isis_vertex *vertex)
                if (adj
                    && isis_sr_adj_sid_find(adj, spftree_pc->family,
                                            ISIS_SR_LAN_BACKUP)) {
-                       if (IS_DEBUG_TILFA)
+                       if (IS_DEBUG_LFA)
                                zlog_debug(
-                                       "ISIS-TI-LFA: %s %s already covered by node protection",
-                                       vtype2string(vertex->type), buf);
+                                       "ISIS-LFA: %s %s already covered by node protection",
+                                       vtype2string(vertex->type),
+                                       vid2string(vertex, buf, sizeof(buf)));
 
                        return -1;
                }
@@ -710,19 +919,21 @@ int isis_lfa_check(struct isis_spftree *spftree_pc, struct isis_vertex *vertex)
 
                route_table = spftree_pc->lfa.old.spftree->route_table_backup;
                if (route_node_lookup(route_table, &vertex->N.ip.p.dest)) {
-                       if (IS_DEBUG_TILFA)
+                       if (IS_DEBUG_LFA)
                                zlog_debug(
-                                       "ISIS-TI-LFA: %s %s already covered by node protection",
-                                       vtype2string(vertex->type), buf);
+                                       "ISIS-LFA: %s %s already covered by node protection",
+                                       vtype2string(vertex->type),
+                                       vid2string(vertex, buf, sizeof(buf)));
 
                        return -1;
                }
        }
 
-       if (IS_DEBUG_TILFA)
+       if (IS_DEBUG_LFA)
                zlog_debug(
-                       "ISIS-TI-LFA: computing repair path(s) of %s %s w.r.t %s",
-                       vtype2string(vertex->type), buf,
+                       "ISIS-LFA: computing repair path(s) of %s %s w.r.t %s",
+                       vtype2string(vertex->type),
+                       vid2string(vertex, buf, sizeof(buf)),
                        lfa_protected_resource2str(
                                &spftree_pc->lfa.protected_resource));
 
@@ -735,7 +946,12 @@ int isis_lfa_check(struct isis_spftree *spftree_pc, struct isis_vertex *vertex)
        isis_spf_node_list_clear(&used_pnodes);
        list_delete(&repair_list);
        if (ret != 0)
-               zlog_warn("ISIS-TI-LFA: failed to compute repair path(s)");
+               zlog_warn(
+                       "ISIS-LFA: failed to compute repair path(s) of %s %s w.r.t %s",
+                       vtype2string(vertex->type),
+                       vid2string(vertex, buf, sizeof(buf)),
+                       lfa_protected_resource2str(
+                               &spftree_pc->lfa.protected_resource));
 
        return ret;
 }
@@ -772,13 +988,6 @@ static bool vertex_is_affected(struct isis_spftree *spftree_root,
                struct isis_vertex *vertex_child;
                struct isis_vertex_adj *vadj;
                bool reverse = false;
-               char buf1[VID2STR_BUFFER];
-               char buf2[VID2STR_BUFFER];
-
-               if (IS_DEBUG_TILFA)
-                       zlog_debug("ISIS-TI-LFA: vertex %s parent %s",
-                                  vid2string(vertex, buf1, sizeof(buf1)),
-                                  vid2string(pvertex, buf2, sizeof(buf2)));
 
                if (p_space && resource->type == LFA_NODE_PROTECTION) {
                        if (isis_spf_node_find(&resource->nodes, vertex->N.id))
@@ -853,15 +1062,11 @@ static void lfa_calc_reach_nodes(struct isis_spftree *spftree,
                if (isis_spf_node_find(nodes, vertex->N.id))
                        continue;
 
-               if (IS_DEBUG_TILFA)
-                       zlog_debug("ISIS-TI-LFA: checking %s",
-                                  vid2string(vertex, buf, sizeof(buf)));
-
                if (!vertex_is_affected(spftree_root, adj_nodes, p_space,
                                        vertex, resource)) {
-                       if (IS_DEBUG_TILFA)
+                       if (IS_DEBUG_LFA)
                                zlog_debug(
-                                       "ISIS-TI-LFA: adding %s",
+                                       "ISIS-LFA: adding %s",
                                        vid2string(vertex, buf, sizeof(buf)));
 
                        isis_spf_node_new(nodes, vertex->N.id);
@@ -875,7 +1080,7 @@ static void lfa_calc_reach_nodes(struct isis_spftree *spftree,
  *
  * @param spftree      IS-IS SPF tree
  *
- * @return             Pointer to new SPF tree structure. 
+ * @return             Pointer to new SPF tree structure.
  */
 struct isis_spftree *isis_spf_reverse_run(const struct isis_spftree *spftree)
 {
@@ -907,18 +1112,17 @@ static void lfa_calc_pq_spaces(struct isis_spftree *spftree_pc,
        spftree_reverse = spftree_pc->lfa.old.spftree_reverse;
        adj_nodes = &spftree->adj_nodes;
 
-       if (IS_DEBUG_TILFA)
-               zlog_debug("ISIS-TI-LFA: computing P-space (self)");
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: computing P-space (self)");
        lfa_calc_reach_nodes(spftree, spftree, adj_nodes, true, resource,
                             &spftree_pc->lfa.p_space);
 
        RB_FOREACH (adj_node, isis_spf_nodes, adj_nodes) {
                if (spf_adj_node_is_affected(adj_node, resource,
                                             spftree->sysid)) {
-                       if (IS_DEBUG_TILFA)
-                               zlog_debug(
-                                       "ISIS-TI-LFA: computing Q-space (%s)",
-                                       print_sys_hostname(adj_node->sysid));
+                       if (IS_DEBUG_LFA)
+                               zlog_debug("ISIS-LFA: computing Q-space (%s)",
+                                          print_sys_hostname(adj_node->sysid));
 
                        /*
                         * Compute the reverse SPF in the behalf of the node
@@ -932,10 +1136,9 @@ static void lfa_calc_pq_spaces(struct isis_spftree *spftree_pc,
                                             resource,
                                             &spftree_pc->lfa.q_space);
                } else {
-                       if (IS_DEBUG_TILFA)
-                               zlog_debug(
-                                       "ISIS-TI-LFA: computing P-space (%s)",
-                                       print_sys_hostname(adj_node->sysid));
+                       if (IS_DEBUG_LFA)
+                               zlog_debug("ISIS-LFA: computing P-space (%s)",
+                                          print_sys_hostname(adj_node->sysid));
                        lfa_calc_reach_nodes(adj_node->lfa.spftree, spftree,
                                             adj_nodes, true, resource,
                                             &adj_node->lfa.p_space);
@@ -961,8 +1164,8 @@ struct isis_spftree *isis_tilfa_compute(struct isis_area *area,
        struct isis_spftree *spftree_pc;
        struct isis_spf_node *adj_node;
 
-       if (IS_DEBUG_TILFA)
-               zlog_debug("ISIS-TI-LFA: computing the P/Q spaces w.r.t. %s",
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: computing TI-LFAs for %s",
                           lfa_protected_resource2str(resource));
 
        /* Populate list of nodes affected by link failure. */
@@ -987,9 +1190,9 @@ struct isis_spftree *isis_tilfa_compute(struct isis_area *area,
        /* Compute the extended P-space and Q-space. */
        lfa_calc_pq_spaces(spftree_pc, resource);
 
-       if (IS_DEBUG_TILFA)
+       if (IS_DEBUG_LFA)
                zlog_debug(
-                       "ISIS-TI-LFA: computing the post convergence SPT w.r.t. %s",
+                       "ISIS-LFA: computing the post convergence SPT w.r.t. %s",
                        lfa_protected_resource2str(resource));
 
        /* Re-run SPF in the local node to find the post-convergence paths. */
@@ -1019,8 +1222,8 @@ int isis_spf_run_neighbors(struct isis_spftree *spftree)
                return -1;
 
        RB_FOREACH (adj_node, isis_spf_nodes, &spftree->adj_nodes) {
-               if (IS_DEBUG_TILFA)
-                       zlog_debug("ISIS-TI-LFA: running SPF on neighbor %s",
+               if (IS_DEBUG_LFA)
+                       zlog_debug("ISIS-LFA: running SPF on neighbor %s",
                                   print_sys_hostname(adj_node->sysid));
 
                /* Compute the SPT on behalf of the neighbor. */
@@ -1034,20 +1237,1028 @@ int isis_spf_run_neighbors(struct isis_spftree *spftree)
        return 0;
 }
 
+/* Find Router ID of PQ node. */
+static struct in_addr *rlfa_pq_node_rtr_id(struct isis_spftree *spftree,
+                                          const struct isis_vertex *vertex_pq)
+{
+       struct isis_lsp *lsp;
+
+       lsp = isis_root_system_lsp(spftree->lspdb, vertex_pq->N.id);
+       if (!lsp)
+               return NULL;
+
+       if (lsp->tlvs->router_cap->router_id.s_addr == INADDR_ANY)
+               return NULL;
+
+       return &lsp->tlvs->router_cap->router_id;
+}
+
+/* Find PQ node by intersecting the P/Q spaces. This is a recursive function. */
+static const struct in_addr *
+rlfa_find_pq_node(struct isis_spftree *spftree_pc,
+                 struct isis_vertex *vertex_dest,
+                 const struct isis_vertex *vertex,
+                 const struct isis_vertex *vertex_child)
+{
+       struct isis_area *area = spftree_pc->area;
+       int level = spftree_pc->level;
+       struct isis_vertex *pvertex;
+       struct listnode *node;
+       bool is_pnode, is_qnode;
+
+       if (!vertex_child)
+               goto parents;
+       if (vertex->type != VTYPE_NONPSEUDO_IS
+           && vertex->type != VTYPE_NONPSEUDO_TE_IS)
+               goto parents;
+       if (!VTYPE_IS(vertex_child->type))
+               vertex_child = NULL;
+
+       /* Check if node is part of the extended P-space and/or Q-space. */
+       is_pnode = lfa_ext_p_space_check(spftree_pc, vertex_dest, vertex);
+       is_qnode = lfa_q_space_check(spftree_pc, vertex);
+
+       if (is_pnode && is_qnode) {
+               const struct in_addr *rtr_id_pq;
+               uint32_t max_metric;
+               struct prefix_list *plist = NULL;
+
+               rtr_id_pq = rlfa_pq_node_rtr_id(spftree_pc, vertex);
+               if (!rtr_id_pq) {
+                       if (IS_DEBUG_LFA) {
+                               char buf[VID2STR_BUFFER];
+
+                               vid2string(vertex, buf, sizeof(buf));
+                               zlog_debug(
+                                       "ISIS-LFA: tentative PQ node (%s %s) doesn't have a router-ID",
+                                       vtype2string(vertex->type), buf);
+                       }
+                       goto parents;
+               }
+
+               max_metric = spftree_pc->lfa.remote.max_metric;
+               if (max_metric && vertex->d_N > max_metric) {
+                       if (IS_DEBUG_LFA)
+                               zlog_debug(
+                                       "ISIS-LFA: skipping PQ node %pI4 (maximum metric)",
+                                       rtr_id_pq);
+                       goto parents;
+               }
+
+               plist = area->rlfa_plist[level - 1];
+               if (plist) {
+                       struct prefix p;
+
+                       p.family = AF_INET;
+                       p.prefixlen = IPV4_MAX_BITLEN;
+                       p.u.prefix4 = *rtr_id_pq;
+                       if (prefix_list_apply(plist, &p) == PREFIX_DENY) {
+                               if (IS_DEBUG_LFA)
+                                       zlog_debug(
+                                               "ISIS-LFA: PQ node %pI4 filtered by prefix-list",
+                                               rtr_id_pq);
+                               goto parents;
+                       }
+               }
+
+               if (IS_DEBUG_LFA)
+                       zlog_debug("ISIS-LFA: found PQ node: %pI4", rtr_id_pq);
+
+               return rtr_id_pq;
+       }
+
+parents:
+       for (ALL_LIST_ELEMENTS_RO(vertex->parents, node, pvertex)) {
+               const struct in_addr *rtr_id_pq;
+
+               rtr_id_pq = rlfa_find_pq_node(spftree_pc, vertex_dest, pvertex,
+                                             vertex);
+               if (rtr_id_pq)
+                       return rtr_id_pq;
+       }
+
+       return NULL;
+}
+
+int rlfa_cmp(const struct rlfa *a, const struct rlfa *b)
+{
+       return prefix_cmp(&a->prefix, &b->prefix);
+}
+
+static struct rlfa *rlfa_add(struct isis_spftree *spftree,
+                            struct isis_vertex *vertex,
+                            struct in_addr pq_address)
+{
+       struct rlfa *rlfa;
+
+       assert(VTYPE_IP(vertex->type));
+       rlfa = XCALLOC(MTYPE_ISIS_RLFA, sizeof(*rlfa));
+       rlfa->prefix = vertex->N.ip.p.dest;
+       rlfa->vertex = vertex;
+       rlfa->pq_address = pq_address;
+       rlfa_tree_add(&spftree->lfa.remote.rlfas, rlfa);
+
+       return rlfa;
+}
+
+static void rlfa_delete(struct isis_spftree *spftree, struct rlfa *rlfa)
+{
+       rlfa_tree_del(&spftree->lfa.remote.rlfas, rlfa);
+       XFREE(MTYPE_ISIS_RLFA, rlfa);
+}
+
+static struct rlfa *rlfa_lookup(struct isis_spftree *spftree,
+                               union prefixconstptr pu)
+{
+       struct rlfa s = {};
+
+       s.prefix = *pu.p;
+       return rlfa_tree_find(&spftree->lfa.remote.rlfas, &s);
+}
+
+static int isis_area_verify_routes_cb(struct thread *thread)
+{
+       struct isis_area *area = THREAD_ARG(thread);
+
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: updating RLFAs in the RIB");
+
+       isis_area_verify_routes(area);
+
+       return 0;
+}
+
+static mpls_label_t rlfa_nexthop_label(struct isis_spftree *spftree,
+                                      struct isis_vertex_adj *vadj,
+                                      struct zapi_rlfa_response *response)
+{
+       struct isis_spf_adj *sadj = vadj->sadj;
+       struct isis_adjacency *adj = sadj->adj;
+
+       /*
+        * Special case to make unit tests work (use implicit-null labels
+        * instead of artifical ones).
+        */
+       if (CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
+               return MPLS_LABEL_IMPLICIT_NULL;
+
+       for (unsigned int i = 0; i < response->nexthop_num; i++) {
+               switch (response->nexthops[i].family) {
+               case AF_INET:
+                       for (unsigned int j = 0; j < adj->ipv4_address_count;
+                            j++) {
+                               struct in_addr addr = adj->ipv4_addresses[j];
+
+                               if (!IPV4_ADDR_SAME(
+                                           &addr,
+                                           &response->nexthops[i].gate.ipv4))
+                                       continue;
+
+                               return response->nexthops[i].label;
+                       }
+                       break;
+               case AF_INET6:
+                       for (unsigned int j = 0; j < adj->ipv6_address_count;
+                            j++) {
+                               struct in6_addr addr = adj->ipv6_addresses[j];
+
+                               if (!IPV6_ADDR_SAME(
+                                           &addr,
+                                           &response->nexthops[i].gate.ipv6))
+                                       continue;
+
+                               return response->nexthops[i].label;
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       return MPLS_INVALID_LABEL;
+}
+
+int isis_rlfa_activate(struct isis_spftree *spftree, struct rlfa *rlfa,
+                      struct zapi_rlfa_response *response)
+{
+       struct isis_area *area = spftree->area;
+       struct isis_vertex *vertex = rlfa->vertex;
+       struct isis_vertex_adj *vadj;
+       struct listnode *node;
+
+       for (ALL_LIST_ELEMENTS_RO(vertex->Adj_N, node, vadj)) {
+               mpls_label_t ldp_label;
+               struct mpls_label_stack *label_stack;
+               size_t num_labels = 0;
+               size_t i = 0;
+
+               ldp_label = rlfa_nexthop_label(spftree, vadj, response);
+               if (ldp_label == MPLS_INVALID_LABEL) {
+                       if (IS_DEBUG_LFA)
+                               zlog_debug(
+                                       "ISIS-LFA: failed to activate RLFA: missing LDP label to reach PQ node through %s",
+                                       sysid_print(vadj->sadj->id));
+                       return -1;
+               }
+
+               if (ldp_label != MPLS_LABEL_IMPLICIT_NULL)
+                       num_labels++;
+               if (response->pq_label != MPLS_LABEL_IMPLICIT_NULL)
+                       num_labels++;
+               if (vadj->sr.present
+                   && vadj->sr.label != MPLS_LABEL_IMPLICIT_NULL)
+                       num_labels++;
+
+               /* Allocate label stack. */
+               label_stack =
+                       XCALLOC(MTYPE_ISIS_NEXTHOP_LABELS,
+                               sizeof(struct mpls_label_stack)
+                                       + num_labels * sizeof(mpls_label_t));
+               label_stack->num_labels = num_labels;
+
+               /* Push label allocated by the nexthop (outer label). */
+               if (ldp_label != MPLS_LABEL_IMPLICIT_NULL)
+                       label_stack->label[i++] = ldp_label;
+               /* Push label allocated by the PQ node (inner label). */
+               if (response->pq_label != MPLS_LABEL_IMPLICIT_NULL)
+                       label_stack->label[i++] = response->pq_label;
+               /* Preserve the original Prefix-SID label when it's present. */
+               if (vadj->sr.present
+                   && vadj->sr.label != MPLS_LABEL_IMPLICIT_NULL)
+                       label_stack->label[i++] = vadj->sr.label;
+
+               vadj->label_stack = label_stack;
+       }
+
+       isis_route_create(&vertex->N.ip.p.dest, &vertex->N.ip.p.src,
+                         vertex->d_N, vertex->depth, &vertex->N.ip.sr,
+                         vertex->Adj_N, true, area,
+                         spftree->route_table_backup);
+       spftree->lfa.protection_counters.rlfa[vertex->N.ip.priority] += 1;
+
+       thread_cancel(&area->t_rlfa_rib_update);
+       thread_add_timer(master, isis_area_verify_routes_cb, area, 2,
+                        &area->t_rlfa_rib_update);
+
+       return 0;
+}
+
+void isis_rlfa_deactivate(struct isis_spftree *spftree, struct rlfa *rlfa)
+{
+       struct isis_area *area = spftree->area;
+       struct isis_vertex *vertex = rlfa->vertex;
+       struct route_node *rn;
+
+       rn = route_node_lookup(spftree->route_table_backup, &rlfa->prefix);
+       if (!rn)
+               return;
+       isis_route_delete(area, rn, spftree->route_table_backup);
+       spftree->lfa.protection_counters.rlfa[vertex->N.ip.priority] -= 1;
+
+       thread_cancel(&area->t_rlfa_rib_update);
+       thread_add_timer(master, isis_area_verify_routes_cb, area, 2,
+                        &area->t_rlfa_rib_update);
+}
+
+void isis_rlfa_list_init(struct isis_spftree *spftree)
+{
+       rlfa_tree_init(&spftree->lfa.remote.rlfas);
+}
+
+void isis_rlfa_list_clear(struct isis_spftree *spftree)
+{
+       while (rlfa_tree_count(&spftree->lfa.remote.rlfas) > 0) {
+               struct rlfa *rlfa;
+
+               rlfa = rlfa_tree_first(&spftree->lfa.remote.rlfas);
+               isis_rlfa_deactivate(spftree, rlfa);
+               rlfa_delete(spftree, rlfa);
+       }
+}
+
+void isis_rlfa_process_ldp_response(struct zapi_rlfa_response *response)
+{
+       struct isis *isis;
+       struct isis_area *area;
+       struct isis_spftree *spftree;
+       struct rlfa *rlfa;
+       enum spf_tree_id tree_id;
+       uint32_t spf_run_id;
+       int level;
+
+       if (response->igp.protocol != ZEBRA_ROUTE_ISIS)
+               return;
+
+       isis = isis_lookup_by_vrfid(response->igp.vrf_id);
+       if (!isis)
+               return;
+
+       area = isis_area_lookup(response->igp.isis.area_tag,
+                               response->igp.vrf_id);
+       if (!area)
+               return;
+
+       tree_id = response->igp.isis.spf.tree_id;
+       if (tree_id != SPFTREE_IPV4 && tree_id != SPFTREE_IPV6) {
+               zlog_warn("ISIS-LFA: invalid SPF tree ID received from LDP");
+               return;
+       }
+
+       level = response->igp.isis.spf.level;
+       if (level != ISIS_LEVEL1 && level != ISIS_LEVEL2) {
+               zlog_warn("ISIS-LFA: invalid IS-IS level received from LDP");
+               return;
+       }
+
+       spf_run_id = response->igp.isis.spf.run_id;
+       spftree = area->spftree[tree_id][level - 1];
+       if (spftree->runcount != spf_run_id)
+               /* Outdated RLFA, ignore... */
+               return;
+
+       rlfa = rlfa_lookup(spftree, &response->destination);
+       if (!rlfa) {
+               zlog_warn(
+                       "ISIS-LFA: couldn't find Remote-LFA %pFX received from LDP",
+                       &response->destination);
+               return;
+       }
+
+       if (response->pq_label != MPLS_INVALID_LABEL) {
+               if (IS_DEBUG_LFA)
+                       zlog_debug(
+                               "ISIS-LFA: activating/updating RLFA for %pFX",
+                               &rlfa->prefix);
+
+               if (isis_rlfa_activate(spftree, rlfa, response) != 0)
+                       isis_rlfa_deactivate(spftree, rlfa);
+       } else {
+               if (IS_DEBUG_LFA)
+                       zlog_debug("ISIS-LFA: deactivating RLFA for %pFX",
+                                  &rlfa->prefix);
+
+               isis_rlfa_deactivate(spftree, rlfa);
+       }
+}
+
+void isis_ldp_rlfa_handle_client_close(struct zapi_client_close_info *info)
+{
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+       struct isis_area *area;
+       struct listnode *node;
+
+       if (!isis)
+               return;
+
+       /* Check if the LDP main client session closed */
+       if (info->proto != ZEBRA_ROUTE_LDP || info->session_id == 0)
+               return;
+
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: LDP is down, deactivating all RLFAs");
+
+       for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+               for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
+                       for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
+                            level++) {
+                               struct isis_spftree *spftree;
+
+                               spftree = area->spftree[tree][level - 1];
+                               isis_rlfa_list_clear(spftree);
+                       }
+               }
+       }
+}
+
+/**
+ * Check if the given SPF vertex needs protection and, if so, attempt to
+ * compute a Remote LFA for it.
+ *
+ * @param spftree_pc   The post-convergence SPF tree
+ * @param vertex       IS-IS SPF vertex to check
+ */
+void isis_rlfa_check(struct isis_spftree *spftree_pc,
+                    struct isis_vertex *vertex)
+{
+       struct isis_spftree *spftree_old = spftree_pc->lfa.old.spftree;
+       struct rlfa *rlfa;
+       const struct in_addr *rtr_id_pq;
+       char buf[VID2STR_BUFFER];
+
+       if (!lfa_check_needs_protection(spftree_pc, vertex)) {
+               if (IS_DEBUG_LFA)
+                       zlog_debug(
+                               "ISIS-LFA: %s %s unaffected by %s",
+                               vtype2string(vertex->type),
+                               vid2string(vertex, buf, sizeof(buf)),
+                               lfa_protected_resource2str(
+                                       &spftree_pc->lfa.protected_resource));
+
+               return;
+       }
+
+       if (IS_DEBUG_LFA)
+               zlog_debug(
+                       "ISIS-LFA: computing repair path(s) of %s %s w.r.t %s",
+                       vtype2string(vertex->type),
+                       vid2string(vertex, buf, sizeof(buf)),
+                       lfa_protected_resource2str(
+                               &spftree_pc->lfa.protected_resource));
+
+       /* Find PQ node. */
+       rtr_id_pq = rlfa_find_pq_node(spftree_pc, vertex, vertex, NULL);
+       if (!rtr_id_pq) {
+               if (IS_DEBUG_LFA)
+                       zlog_debug("ISIS-LFA: no acceptable PQ node found");
+               return;
+       }
+
+       /* Store valid RLFA and store LDP label for the PQ node. */
+       rlfa = rlfa_add(spftree_old, vertex, *rtr_id_pq);
+
+       /* Register RLFA with LDP. */
+       if (isis_zebra_rlfa_register(spftree_old, rlfa) != 0)
+               rlfa_delete(spftree_old, rlfa);
+}
+
+/**
+ * Compute the Remote LFA backup paths for a given protected interface.
+ *
+ * @param area           IS-IS area
+ * @param spftree        IS-IS SPF tree
+ * @param spftree_reverse IS-IS Reverse SPF tree
+ * @param max_metric     Remote LFA maximum metric
+ * @param resource       Protected resource
+ *
+ * @return               Pointer to the post-convergence SPF tree
+ */
+struct isis_spftree *isis_rlfa_compute(struct isis_area *area,
+                                      struct isis_spftree *spftree,
+                                      struct isis_spftree *spftree_reverse,
+                                      uint32_t max_metric,
+                                      struct lfa_protected_resource *resource)
+{
+       struct isis_spftree *spftree_pc;
+
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: computing remote LFAs for %s",
+                          lfa_protected_resource2str(resource));
+
+       /* Create post-convergence SPF tree. */
+       spftree_pc = isis_spftree_new(area, spftree->lspdb, spftree->sysid,
+                                     spftree->level, spftree->tree_id,
+                                     SPF_TYPE_RLFA, spftree->flags);
+       spftree_pc->lfa.old.spftree = spftree;
+       spftree_pc->lfa.old.spftree_reverse = spftree_reverse;
+       spftree_pc->lfa.remote.max_metric = max_metric;
+       spftree_pc->lfa.protected_resource = *resource;
+
+       /* Compute the extended P-space and Q-space. */
+       lfa_calc_pq_spaces(spftree_pc, resource);
+
+       if (IS_DEBUG_LFA)
+               zlog_debug(
+                       "ISIS-LFA: computing the post convergence SPT w.r.t. %s",
+                       lfa_protected_resource2str(resource));
+
+       /* Re-run SPF in the local node to find the post-convergence paths. */
+       isis_run_spf(spftree_pc);
+
+       return spftree_pc;
+}
+
+/* Calculate the distance from the root node to the given IP destination. */
+static int lfa_calc_dist_destination(struct isis_spftree *spftree,
+                                    const struct isis_vertex *vertex_N,
+                                    uint32_t *distance)
+{
+       struct isis_vertex *vertex, *vertex_best = NULL;
+
+       switch (spftree->family) {
+       case AF_INET:
+               for (int vtype = VTYPE_IPREACH_INTERNAL;
+                    vtype <= VTYPE_IPREACH_TE; vtype++) {
+                       vertex = isis_find_vertex(
+                               &spftree->paths, &vertex_N->N.ip.p.dest, vtype);
+                       if (!vertex)
+                               continue;
+
+                       /* Pick vertex with the best metric. */
+                       if (!vertex_best || vertex_best->d_N > vertex->d_N)
+                               vertex_best = vertex;
+               }
+               break;
+       case AF_INET6:
+               for (int vtype = VTYPE_IP6REACH_INTERNAL;
+                    vtype <= VTYPE_IP6REACH_EXTERNAL; vtype++) {
+                       vertex = isis_find_vertex(
+                               &spftree->paths, &vertex_N->N.ip.p.dest, vtype);
+                       if (!vertex)
+                               continue;
+
+                       /* Pick vertex with the best metric. */
+                       if (!vertex_best || vertex_best->d_N > vertex->d_N)
+                               vertex_best = vertex;
+               }
+               break;
+       default:
+               break;
+       }
+
+       if (!vertex_best)
+               return -1;
+
+       assert(VTYPE_IP(vertex_best->type));
+       vertex_best = listnode_head(vertex_best->parents);
+       *distance = vertex_best->d_N;
+
+       return 0;
+}
+
+/* Calculate the distance from the root node to the given node. */
+static int lfa_calc_dist_node(struct isis_spftree *spftree,
+                             const uint8_t *sysid, uint32_t *distance)
+{
+       struct isis_vertex *vertex, *vertex_best = NULL;
+
+       for (int vtype = VTYPE_PSEUDO_IS; vtype <= VTYPE_NONPSEUDO_TE_IS;
+            vtype++) {
+               vertex = isis_find_vertex(&spftree->paths, sysid, vtype);
+               if (!vertex)
+                       continue;
+
+               /* Pick vertex with the best metric. */
+               if (!vertex_best || vertex_best->d_N > vertex->d_N)
+                       vertex_best = vertex;
+       }
+
+       if (!vertex_best)
+               return -1;
+
+       *distance = vertex_best->d_N;
+
+       return 0;
+}
+
+/*
+ * Check loop-free criterion (RFC 5286's inequality 1):
+ * - Dist_opt(N, D) < Dist_opt(N, S) + Dist_opt(S, D)
+ */
+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)
+{
+       struct isis_spf_node *node_N;
+       uint32_t dist_N_D;
+       uint32_t dist_N_S;
+       uint32_t dist_S_D;
+
+       node_N = isis_spf_node_find(&spftree->adj_nodes, sadj_N->id);
+       assert(node_N);
+
+       /* Distance from N to D. */
+       if (lfa_calc_dist_destination(node_N->lfa.spftree, vertex_S_D,
+                                     &dist_N_D)
+           != 0)
+               return false;
+
+       /* Distance from N to S (or PN). */
+       if (CHECK_FLAG(sadj_primary->flags, F_ISIS_SPF_ADJ_BROADCAST)) {
+               static uint8_t pn_sysid[ISIS_SYS_ID_LEN + 1];
+
+               memcpy(pn_sysid, sadj_primary->id, ISIS_SYS_ID_LEN + 1);
+               if (lfa_calc_dist_node(node_N->lfa.spftree, pn_sysid, &dist_N_S)
+                   != 0)
+                       return false;
+       } else {
+               static uint8_t root_sysid[ISIS_SYS_ID_LEN + 1];
+
+               memcpy(root_sysid, spftree->sysid, ISIS_SYS_ID_LEN);
+               LSP_PSEUDO_ID(root_sysid) = 0;
+               if (lfa_calc_dist_node(node_N->lfa.spftree, root_sysid,
+                                      &dist_N_S)
+                   != 0)
+                       return false;
+       }
+
+       /* Distance from S (or PN) to D. */
+       vertex_S_D = listnode_head(vertex_S_D->parents);
+       dist_S_D = vertex_S_D->d_N;
+       if (CHECK_FLAG(sadj_primary->flags, F_ISIS_SPF_ADJ_BROADCAST))
+               dist_S_D -= sadj_primary->metric;
+
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: loop-free check: %u < %u + %u", dist_N_D,
+                          dist_N_S, dist_S_D);
+
+       if (dist_N_D < (dist_N_S + dist_S_D)) {
+               *lfa_metric = sadj_N->metric + dist_N_D;
+               return true;
+       }
+
+       return false;
+}
+
+/*
+ * Check loop-free criterion (RFC 5286's inequality 2):
+ * - Distance_opt(N, D) < Distance_opt(S, D)
+ */
+static bool clfa_downstream_check(struct isis_spftree *spftree,
+                                 struct isis_vertex *vertex_S_D,
+                                 struct isis_spf_adj *sadj_N)
+{
+       struct isis_spf_node *node_N;
+       uint32_t dist_N_D;
+       uint32_t dist_S_D;
+
+       node_N = isis_spf_node_find(&spftree->adj_nodes, sadj_N->id);
+       assert(node_N);
+
+       /* Distance from N to D. */
+       if (lfa_calc_dist_destination(node_N->lfa.spftree, vertex_S_D,
+                                     &dist_N_D)
+           != 0)
+               return false;
+
+       /* Distance from S (or PN) to D. */
+       vertex_S_D = listnode_head(vertex_S_D->parents);
+       dist_S_D = vertex_S_D->d_N;
+
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: downstream check: %u < %u", dist_N_D,
+                          dist_S_D);
+
+       if (dist_N_D < dist_S_D)
+               return true;
+
+       return false;
+}
+
+/*
+ * Check loop-free criterion (RFC 5286's inequality 3):
+ * - Dist_opt(N, D) < Dist_opt(N, E) + Dist_opt(E, D)
+ */
+static bool clfa_node_protecting_check(struct isis_spftree *spftree,
+                                      struct isis_vertex *vertex_S_D,
+                                      struct isis_spf_adj *sadj_N,
+                                      struct isis_spf_adj *sadj_E)
+{
+       struct isis_spf_node *node_N, *node_E;
+       uint32_t dist_N_D;
+       uint32_t dist_N_E;
+       uint32_t dist_E_D;
+
+       node_N = isis_spf_node_find(&spftree->adj_nodes, sadj_N->id);
+       assert(node_N);
+       node_E = isis_spf_node_find(&spftree->adj_nodes, sadj_E->id);
+       assert(node_E);
+
+       /* Distance from N to D. */
+       if (lfa_calc_dist_destination(node_N->lfa.spftree, vertex_S_D,
+                                     &dist_N_D)
+           != 0)
+               return false;
+
+       /* Distance from N to E. */
+       if (lfa_calc_dist_node(node_N->lfa.spftree, node_E->sysid, &dist_N_E)
+           != 0)
+               return false;
+
+       /* Distance from E to D. */
+       if (lfa_calc_dist_destination(node_E->lfa.spftree, vertex_S_D,
+                                     &dist_E_D)
+           != 0)
+               return false;
+
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: node protecting check: %u < %u + %u",
+                          dist_N_D, dist_N_E, dist_E_D);
+
+       return (dist_N_D < (dist_N_E + dist_E_D));
+}
+
+static struct list *
+isis_lfa_tiebreakers(struct isis_area *area, struct isis_spftree *spftree,
+                    struct lfa_protected_resource *resource,
+                    struct isis_vertex *vertex,
+                    struct isis_spf_adj *sadj_primary, struct list *lfa_list)
+{
+       struct lfa_tiebreaker *tie_b;
+       int level = spftree->level;
+       struct list *filtered_lfa_list;
+       struct list *tent_lfa_list;
+
+       filtered_lfa_list = list_dup(lfa_list);
+       filtered_lfa_list->del = NULL;
+
+       if (listcount(filtered_lfa_list) == 1)
+               return filtered_lfa_list;
+
+       /* Check tiebreakers in ascending order by index. */
+       frr_each (lfa_tiebreaker_tree, &area->lfa_tiebreakers[level - 1],
+                 tie_b) {
+               struct isis_vertex_adj *lfa;
+               struct listnode *node, *nnode;
+               uint32_t best_metric = UINT32_MAX;
+
+               tent_lfa_list = list_dup(filtered_lfa_list);
+
+               switch (tie_b->type) {
+               case LFA_TIEBREAKER_DOWNSTREAM:
+                       for (ALL_LIST_ELEMENTS(tent_lfa_list, node, nnode,
+                                              lfa)) {
+                               if (clfa_downstream_check(spftree, vertex,
+                                                         lfa->sadj))
+                                       continue;
+
+                               if (IS_DEBUG_LFA)
+                                       zlog_debug(
+                                               "ISIS-LFA: LFA %s doesn't satisfy the downstream condition",
+                                               print_sys_hostname(
+                                                       lfa->sadj->id));
+                               listnode_delete(tent_lfa_list, lfa);
+                       }
+                       break;
+               case LFA_TIEBREAKER_LOWEST_METRIC:
+                       /* Find the best metric first. */
+                       for (ALL_LIST_ELEMENTS_RO(tent_lfa_list, node, lfa)) {
+                               if (lfa->lfa_metric < best_metric)
+                                       best_metric = lfa->lfa_metric;
+                       }
+
+                       /* Remove LFAs that don't have the best metric. */
+                       for (ALL_LIST_ELEMENTS(tent_lfa_list, node, nnode,
+                                              lfa)) {
+                               if (lfa->lfa_metric == best_metric)
+                                       continue;
+
+                               if (IS_DEBUG_LFA)
+                                       zlog_debug(
+                                               "ISIS-LFA: LFA %s doesn't have the lowest cost metric",
+                                               print_sys_hostname(
+                                                       lfa->sadj->id));
+                               listnode_delete(tent_lfa_list, lfa);
+                       }
+                       break;
+               case LFA_TIEBREAKER_NODE_PROTECTING:
+                       for (ALL_LIST_ELEMENTS(tent_lfa_list, node, nnode,
+                                              lfa)) {
+                               if (clfa_node_protecting_check(spftree, vertex,
+                                                              lfa->sadj,
+                                                              sadj_primary))
+                                       continue;
+
+                               if (IS_DEBUG_LFA)
+                                       zlog_debug(
+                                               "ISIS-LFA: LFA %s doesn't provide node protection",
+                                               print_sys_hostname(
+                                                       lfa->sadj->id));
+                               listnode_delete(tent_lfa_list, lfa);
+                       }
+                       break;
+               }
+
+               /*
+                * Decide what to do next based on the number of remaining LFAs.
+                */
+               switch (listcount(tent_lfa_list)) {
+               case 0:
+                       /*
+                        * Ignore this tie-breaker since it excluded all LFAs.
+                        * Move on to the next one (if any).
+                        */
+                       list_delete(&tent_lfa_list);
+                       break;
+               case 1:
+                       /* Finish tie-breaking once we get a single LFA. */
+                       list_delete(&filtered_lfa_list);
+                       filtered_lfa_list = tent_lfa_list;
+                       return filtered_lfa_list;
+               default:
+                       /*
+                        * We still have two or more LFAs. Move on to the next
+                        * tie-breaker (if any).
+                        */
+                       list_delete(&filtered_lfa_list);
+                       filtered_lfa_list = tent_lfa_list;
+                       break;
+               }
+       }
+
+       return filtered_lfa_list;
+}
+
+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 listnode *vnode, *snode;
+       int level = spftree->level;
+
+       resource->type = LFA_LINK_PROTECTION;
+
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: computing local LFAs for %s",
+                          lfa_protected_resource2str(resource));
+
+       for (ALL_QUEUE_ELEMENTS_RO(&spftree->paths, vnode, vertex)) {
+               struct list *lfa_list;
+               struct list *filtered_lfa_list;
+               struct isis_spf_adj *sadj_N;
+               struct isis_vertex_adj *vadj_primary;
+               struct isis_spf_adj *sadj_primary;
+               bool allow_ecmp;
+               uint32_t best_metric = UINT32_MAX;
+               char buf[VID2STR_BUFFER];
+
+               if (!VTYPE_IP(vertex->type))
+                       continue;
+
+               vid2string(vertex, buf, sizeof(buf));
+
+               if (!spf_vertex_check_is_affected(vertex, spftree->sysid,
+                                                 resource)) {
+                       if (IS_DEBUG_LFA)
+                               zlog_debug(
+                                       "ISIS-LFA: %s %s unaffected by %s",
+                                       vtype2string(vertex->type), buf,
+                                       lfa_protected_resource2str(resource));
+                       continue;
+               }
+
+               if (IS_DEBUG_LFA)
+                       zlog_debug("ISIS-LFA: checking %s %s w.r.t %s",
+                                  vtype2string(vertex->type), buf,
+                                  lfa_protected_resource2str(resource));
+
+               if (vertex->N.ip.priority
+                   > area->lfa_priority_limit[level - 1]) {
+                       if (IS_DEBUG_LFA)
+                               zlog_debug(
+                                       "ISIS-LFA: skipping computing LFAs due to low prefix priority");
+                       continue;
+               }
+
+               vadj_primary = listnode_head(vertex->Adj_N);
+               sadj_primary = vadj_primary->sadj;
+
+               /*
+                * Loop over list of SPF adjacencies and compute a list of
+                * preliminary LFAs.
+                */
+               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;
+                       struct isis_vertex_adj *lfa;
+                       struct isis_prefix_sid *psid = NULL;
+                       bool last_hop = false;
+
+                       /* Skip pseudonodes. */
+                       if (LSP_PSEUDO_ID(sadj_N->id))
+                               continue;
+
+                       /*
+                        * Skip nexthops that are along a link whose cost is
+                        * infinite.
+                        */
+                       if (CHECK_FLAG(sadj_N->flags,
+                                      F_ISIS_SPF_ADJ_METRIC_INFINITY))
+                               continue;
+
+                       /* Skip nexthops that have the overload bit set. */
+                       if (spftree->mtid != ISIS_MT_IPV4_UNICAST) {
+                               struct isis_mt_router_info *mt_router_info;
+
+                               mt_router_info =
+                                       isis_tlvs_lookup_mt_router_info(
+                                               sadj_N->lsp->tlvs,
+                                               spftree->mtid);
+                               if (mt_router_info && mt_router_info->overload)
+                                       continue;
+                       } else if (ISIS_MASK_LSP_OL_BIT(
+                                          sadj_N->lsp->hdr.lsp_bits))
+                               continue;
+
+                       /* Skip primary nexthop. */
+                       if (spf_adj_check_is_affected(sadj_N, resource, NULL,
+                                                     false))
+                               continue;
+
+                       /* Skip excluded interfaces as per the configuration. */
+                       if (circuit
+                           && isis_lfa_excluded_iface_check(
+                                      circuit, level,
+                                      sadj_N->adj->circuit->interface->name))
+                               continue;
+
+                       if (IS_DEBUG_LFA)
+                               zlog_debug(
+                                       "ISIS-LFA: checking candidate LFA %s",
+                                       print_sys_hostname(sadj_N->id));
+
+                       /* Check loop-free criterion. */
+                       if (!clfa_loop_free_check(spftree, vertex, sadj_primary,
+                                                 sadj_N, &lfa_metric)) {
+                               if (IS_DEBUG_LFA)
+                                       zlog_debug(
+                                               "ISIS-LFA: LFA condition not met for %s",
+                                               print_sys_hostname(sadj_N->id));
+                               continue;
+                       }
+
+                       if (lfa_metric < best_metric)
+                               best_metric = lfa_metric;
+
+                       if (IS_DEBUG_LFA)
+                               zlog_debug(
+                                       "ISIS-LFA: %s is a valid loop-free alternate",
+                                       print_sys_hostname(sadj_N->id));
+
+                       if (vertex->N.ip.sr.present) {
+                               psid = &vertex->N.ip.sr.sid;
+                               if (lfa_metric == sadj_N->metric)
+                                       last_hop = true;
+                       }
+                       lfa = isis_vertex_adj_add(spftree, vertex, lfa_list,
+                                                 sadj_N, psid, last_hop);
+                       lfa->lfa_metric = lfa_metric;
+               }
+
+               if (list_isempty(lfa_list)) {
+                       if (IS_DEBUG_LFA)
+                               zlog_debug(
+                                       "ISIS-LFA: no valid local LFAs found");
+                       list_delete(&lfa_list);
+                       continue;
+               }
+
+               SET_FLAG(vertex->flags, F_ISIS_VERTEX_LFA_PROTECTED);
+
+               /* Check tie-breakers. */
+               filtered_lfa_list =
+                       isis_lfa_tiebreakers(area, spftree, resource, vertex,
+                                            sadj_primary, lfa_list);
+
+               /* Create backup route using the best LFAs. */
+               allow_ecmp = area->lfa_load_sharing[level - 1];
+               isis_route_create(&vertex->N.ip.p.dest, &vertex->N.ip.p.src,
+                                 best_metric, vertex->depth, &vertex->N.ip.sr,
+                                 filtered_lfa_list, allow_ecmp, area,
+                                 spftree->route_table_backup);
+               spftree->lfa.protection_counters.lfa[vertex->N.ip.priority] +=
+                       1;
+
+               list_delete(&filtered_lfa_list);
+               list_delete(&lfa_list);
+       }
+}
+
+static void isis_spf_run_tilfa(struct isis_area *area,
+                              struct isis_circuit *circuit,
+                              struct isis_spftree *spftree,
+                              struct isis_spftree *spftree_reverse,
+                              struct lfa_protected_resource *resource)
+{
+       struct isis_spftree *spftree_pc_link;
+       struct isis_spftree *spftree_pc_node;
+
+       /* Compute node protecting repair paths first (if necessary). */
+       if (circuit->tilfa_node_protection[spftree->level - 1]) {
+               resource->type = LFA_NODE_PROTECTION;
+               spftree_pc_node = isis_tilfa_compute(area, spftree,
+                                                    spftree_reverse, resource);
+               isis_spftree_del(spftree_pc_node);
+       }
+
+       /* Compute link protecting repair paths. */
+       resource->type = LFA_LINK_PROTECTION;
+       spftree_pc_link =
+               isis_tilfa_compute(area, spftree, spftree_reverse, resource);
+       isis_spftree_del(spftree_pc_link);
+}
+
 /**
- * Run the TI-LFA algorithm for all proctected interfaces.
+ * Run the LFA/RLFA/TI-LFA algorithms for all protected interfaces.
  *
  * @param area         IS-IS area
  * @param spftree      IS-IS SPF tree
  */
 void isis_spf_run_lfa(struct isis_area *area, struct isis_spftree *spftree)
 {
-       struct isis_spftree *spftree_reverse;
+       struct isis_spftree *spftree_reverse = NULL;
        struct isis_circuit *circuit;
        struct listnode *node;
+       int level = spftree->level;
 
        /* Run reverse SPF locally. */
-       spftree_reverse = isis_spf_reverse_run(spftree);
+       if (area->rlfa_protected_links[level - 1] > 0
+           || area->tilfa_protected_links[level - 1] > 0)
+               spftree_reverse = isis_spf_reverse_run(spftree);
 
        /* Run forward SPF on all adjacent routers. */
        isis_spf_run_neighbors(spftree);
@@ -1056,20 +2267,19 @@ void isis_spf_run_lfa(struct isis_area *area, struct isis_spftree *spftree)
        for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
                struct lfa_protected_resource resource = {};
                struct isis_adjacency *adj;
-               struct isis_spftree *spftree_pc_link;
-               struct isis_spftree *spftree_pc_node;
                static uint8_t null_sysid[ISIS_SYS_ID_LEN + 1];
 
-               if (!(circuit->is_type & spftree->level))
+               if (!(circuit->is_type & level))
                        continue;
 
-               if (!circuit->tilfa_protection[spftree->level - 1])
+               if (!circuit->lfa_protection[level - 1]
+                   && !circuit->tilfa_protection[level - 1])
                        continue;
 
                /* Fill in the protected resource. */
                switch (circuit->circ_type) {
                case CIRCUIT_T_BROADCAST:
-                       if (spftree->level == 1)
+                       if (level == ISIS_LEVEL1)
                                memcpy(resource.adjacency,
                                       circuit->u.bc.l1_desig_is,
                                       ISIS_SYS_ID_LEN + 1);
@@ -1093,20 +2303,32 @@ void isis_spf_run_lfa(struct isis_area *area, struct isis_spftree *spftree)
                        continue;
                }
 
-               /* Compute node protecting repair paths first (if necessary). */
-               if (circuit->tilfa_node_protection[spftree->level - 1]) {
-                       resource.type = LFA_NODE_PROTECTION;
-                       spftree_pc_node = isis_tilfa_compute(
-                               area, spftree, spftree_reverse, &resource);
-                       isis_spftree_del(spftree_pc_node);
+               if (circuit->lfa_protection[level - 1]) {
+                       /* Run local LFA. */
+                       isis_lfa_compute(area, circuit, spftree, &resource);
+
+                       if (circuit->rlfa_protection[level - 1]) {
+                               struct isis_spftree *spftree_pc;
+                               uint32_t max_metric;
+
+                               /* Run remote LFA. */
+                               assert(spftree_reverse);
+                               max_metric =
+                                       circuit->rlfa_max_metric[level - 1];
+                               spftree_pc = isis_rlfa_compute(
+                                       area, spftree, spftree_reverse,
+                                       max_metric, &resource);
+                               listnode_add(spftree->lfa.remote.pc_spftrees,
+                                            spftree_pc);
+                       }
+               } else if (circuit->tilfa_protection[level - 1]) {
+                       /* Run TI-LFA. */
+                       assert(spftree_reverse);
+                       isis_spf_run_tilfa(area, circuit, spftree,
+                                          spftree_reverse, &resource);
                }
-
-               /* Compute link protecting repair paths. */
-               resource.type = LFA_LINK_PROTECTION;
-               spftree_pc_link = isis_tilfa_compute(
-                       area, spftree, spftree_reverse, &resource);
-               isis_spftree_del(spftree_pc_link);
        }
 
-       isis_spftree_del(spftree_reverse);
+       if (spftree_reverse)
+               isis_spftree_del(spftree_reverse);
 }
index 835618760c0f637bd975d730d964579ade830b62..65891cae44313e81ed0f56fe1651facb6ca62d55 100644 (file)
 #ifndef _FRR_ISIS_LFA_H
 #define _FRR_ISIS_LFA_H
 
+#include "lib/typesafe.h"
+#include "lib/zclient.h"
+
+PREDECL_RBTREE_UNIQ(lfa_tiebreaker_tree)
+PREDECL_RBTREE_UNIQ(rlfa_tree)
+
+enum lfa_tiebreaker_type {
+       LFA_TIEBREAKER_DOWNSTREAM = 0,
+       LFA_TIEBREAKER_LOWEST_METRIC,
+       LFA_TIEBREAKER_NODE_PROTECTING,
+};
+
+struct lfa_tiebreaker {
+       struct lfa_tiebreaker_tree_item entry;
+       uint8_t index;
+       enum lfa_tiebreaker_type type;
+       struct isis_area *area;
+};
+int lfa_tiebreaker_cmp(const struct lfa_tiebreaker *a,
+                      const struct lfa_tiebreaker *b);
+DECLARE_RBTREE_UNIQ(lfa_tiebreaker_tree, struct lfa_tiebreaker, entry,
+                   lfa_tiebreaker_cmp)
+
+struct rlfa {
+       struct rlfa_tree_item entry;
+       struct prefix prefix;
+       struct isis_vertex *vertex;
+       struct in_addr pq_address;
+};
+int rlfa_cmp(const struct rlfa *a, const struct rlfa *b);
+DECLARE_RBTREE_UNIQ(rlfa_tree, struct rlfa, entry, rlfa_cmp)
+
 enum isis_tilfa_sid_type {
        TILFA_SID_PREFIX = 1,
        TILFA_SID_ADJ,
@@ -37,6 +69,20 @@ struct isis_tilfa_sid {
        } value;
 };
 
+enum spf_prefix_priority {
+       SPF_PREFIX_PRIO_CRITICAL = 0,
+       SPF_PREFIX_PRIO_HIGH,
+       SPF_PREFIX_PRIO_MEDIUM,
+       SPF_PREFIX_PRIO_LOW,
+       SPF_PREFIX_PRIO_MAX,
+};
+
+struct spf_prefix_priority_acl {
+       char *name;
+       struct access_list *list_v4;
+       struct access_list *list_v6;
+};
+
 RB_HEAD(isis_spf_nodes, isis_spf_node);
 RB_PROTOTYPE(isis_spf_nodes, isis_spf_node, entry, isis_spf_node_compare)
 struct isis_spf_node {
@@ -89,14 +135,45 @@ struct isis_spf_node *isis_spf_node_new(struct isis_spf_nodes *nodes,
                                        const uint8_t *sysid);
 struct isis_spf_node *isis_spf_node_find(const struct isis_spf_nodes *nodes,
                                         const uint8_t *sysid);
+void isis_lfa_tiebreakers_init(struct isis_area *area, int level);
+void isis_lfa_tiebreakers_clear(struct isis_area *area, int level);
+struct lfa_tiebreaker *isis_lfa_tiebreaker_add(struct isis_area *area,
+                                              int level, uint8_t index,
+                                              enum lfa_tiebreaker_type type);
+void isis_lfa_tiebreaker_delete(struct isis_area *area, int level,
+                               struct lfa_tiebreaker *tie_b);
+void isis_lfa_excluded_ifaces_init(struct isis_circuit *circuit, int level);
+void isis_lfa_excluded_ifaces_clear(struct isis_circuit *circuit, int level);
+void isis_lfa_excluded_iface_add(struct isis_circuit *circuit, int level,
+                                const char *ifname);
+void isis_lfa_excluded_iface_delete(struct isis_circuit *circuit, int level,
+                                   const char *ifname);
+bool isis_lfa_excluded_iface_check(struct isis_circuit *circuit, int level,
+                                  const char *ifname);
 bool isis_lfa_excise_adj_check(const struct isis_spftree *spftree,
                               const uint8_t *id);
 bool isis_lfa_excise_node_check(const struct isis_spftree *spftree,
                                const uint8_t *id);
 struct isis_spftree *isis_spf_reverse_run(const struct isis_spftree *spftree);
 int isis_spf_run_neighbors(struct isis_spftree *spftree);
+int isis_rlfa_activate(struct isis_spftree *spftree, struct rlfa *rlfa,
+                      struct zapi_rlfa_response *response);
+void isis_rlfa_deactivate(struct isis_spftree *spftree, struct rlfa *rlfa);
+void isis_rlfa_list_init(struct isis_spftree *spftree);
+void isis_rlfa_list_clear(struct isis_spftree *spftree);
+void isis_rlfa_process_ldp_response(struct zapi_rlfa_response *response);
+void isis_ldp_rlfa_handle_client_close(struct zapi_client_close_info *info);
+void isis_rlfa_check(struct isis_spftree *spftree, struct isis_vertex *vertex);
+struct isis_spftree *isis_rlfa_compute(struct isis_area *area,
+                                      struct isis_spftree *spftree,
+                                      struct isis_spftree *spftree_reverse,
+                                      uint32_t max_metric,
+                                      struct lfa_protected_resource *resource);
+void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
+                     struct isis_spftree *spftree,
+                     struct lfa_protected_resource *resource);
 void isis_spf_run_lfa(struct isis_area *area, struct isis_spftree *spftree);
-int isis_lfa_check(struct isis_spftree *spftree, struct isis_vertex *vertex);
+int isis_tilfa_check(struct isis_spftree *spftree, struct isis_vertex *vertex);
 struct isis_spftree *
 isis_tilfa_compute(struct isis_area *area, struct isis_spftree *spftree,
                   struct isis_spftree *spftree_reverse,
index d8ad4cd510ab2434c8713b5930a416fcd4fb30c0..47225ea2c3553f1425a36532ad137d0bfdad863e 100644 (file)
@@ -973,7 +973,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                 */
                if (area->newmetric) {
                        if (IS_MPLS_TE(area->mta)
-                           && area->mta->router_id.s_addr != 0)
+                           && area->mta->router_id.s_addr != INADDR_ANY)
                                id.s_addr = area->mta->router_id.s_addr;
                        lsp_debug(
                                "ISIS (%s): Adding router ID also as TE router ID tlv.",
index 22df3ff37e4d31f90f36287e8eed1cdf23d0c88a..1b04f4f7a0938112ac0e08ee361fdb4f81001c32 100644 (file)
@@ -242,8 +242,12 @@ int main(int argc, char **argv, char **envp)
         */
        isis_error_init();
        access_list_init();
+       access_list_add_hook(isis_filter_update);
+       access_list_delete_hook(isis_filter_update);
        isis_vrf_init();
        prefix_list_init();
+       prefix_list_add_hook(isis_prefix_list_update);
+       prefix_list_delete_hook(isis_prefix_list_update);
        isis_init();
        isis_circuit_init();
 #ifdef FABRICD
index a64decc14fbeb7d1c0d458b2d4e5e0c9c821fdf3..f716e060cd59828c0185148a54e23e96ef5391cc 100644 (file)
@@ -45,3 +45,5 @@ DEFINE_MTYPE(ISISD, ISIS_DICT_NODE, "ISIS dictionary node")
 DEFINE_MTYPE(ISISD, ISIS_EXT_ROUTE, "ISIS redistributed route")
 DEFINE_MTYPE(ISISD, ISIS_EXT_INFO, "ISIS redistributed route info")
 DEFINE_MTYPE(ISISD, ISIS_MPLS_TE, "ISIS MPLS_TE parameters")
+DEFINE_MTYPE(ISISD, ISIS_ACL_NAME, "ISIS access-list name")
+DEFINE_MTYPE(ISISD, ISIS_PLIST_NAME, "ISIS prefix-list name")
index 6b63b3ccb8cbad1e210ccfd5cb0c93d45c44d6d1..5bcd2a3983528b98e7ae2af8b187fc9103ab5574 100644 (file)
@@ -44,5 +44,7 @@ DECLARE_MTYPE(ISIS_DICT_NODE)
 DECLARE_MTYPE(ISIS_EXT_ROUTE)
 DECLARE_MTYPE(ISIS_EXT_INFO)
 DECLARE_MTYPE(ISIS_MPLS_TE)
+DECLARE_MTYPE(ISIS_ACL_NAME)
+DECLARE_MTYPE(ISIS_PLIST_NAME)
 
 #endif /* _QUAGGA_ISIS_MEMORY_H */
index 2d3c7e1e38b31d50176eb48b20969513ec3068c0..a02e6a45b183139440a2d1baed04e70b589a2a44 100644 (file)
@@ -193,6 +193,30 @@ const struct frr_yang_module_info frr_isisd_info = {
                                .modify = isis_instance_spf_minimum_interval_level_2_modify,
                        },
                },
+               {
+                       .xpath = "/frr-isisd:isis/instance/spf/prefix-priorities/critical/access-list-name",
+                       .cbs = {
+                               .cli_show = cli_show_isis_spf_prefix_priority,
+                               .modify = isis_instance_spf_prefix_priorities_critical_access_list_name_modify,
+                               .destroy = isis_instance_spf_prefix_priorities_critical_access_list_name_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-isisd:isis/instance/spf/prefix-priorities/high/access-list-name",
+                       .cbs = {
+                               .cli_show = cli_show_isis_spf_prefix_priority,
+                               .modify = isis_instance_spf_prefix_priorities_high_access_list_name_modify,
+                               .destroy = isis_instance_spf_prefix_priorities_high_access_list_name_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-isisd:isis/instance/spf/prefix-priorities/medium/access-list-name",
+                       .cbs = {
+                               .cli_show = cli_show_isis_spf_prefix_priority,
+                               .modify = isis_instance_spf_prefix_priorities_medium_access_list_name_modify,
+                               .destroy = isis_instance_spf_prefix_priorities_medium_access_list_name_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-isisd:isis/instance/area-password",
                        .cbs = {
@@ -431,6 +455,80 @@ const struct frr_yang_module_info frr_isisd_info = {
                                .modify = isis_instance_multi_topology_ipv6_dstsrc_overload_modify,
                        },
                },
+               {
+                       .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/load-sharing",
+                       .cbs = {
+                               .cli_show = cli_show_isis_frr_lfa_load_sharing,
+                               .modify = isis_instance_fast_reroute_level_1_lfa_load_sharing_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/priority-limit",
+                       .cbs = {
+                               .cli_show = cli_show_isis_frr_lfa_priority_limit,
+                               .modify = isis_instance_fast_reroute_level_1_lfa_priority_limit_modify,
+                               .destroy = isis_instance_fast_reroute_level_1_lfa_priority_limit_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker",
+                       .cbs = {
+                               .cli_show = cli_show_isis_frr_lfa_tiebreaker,
+                               .create = isis_instance_fast_reroute_level_1_lfa_tiebreaker_create,
+                               .destroy = isis_instance_fast_reroute_level_1_lfa_tiebreaker_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker/type",
+                       .cbs = {
+                               .modify = isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/remote-lfa/prefix-list",
+                       .cbs = {
+                               .cli_show = cli_show_isis_frr_remote_lfa_plist,
+                               .modify = isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_modify,
+                               .destroy = isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/load-sharing",
+                       .cbs = {
+                               .cli_show = cli_show_isis_frr_lfa_load_sharing,
+                               .modify = isis_instance_fast_reroute_level_2_lfa_load_sharing_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/priority-limit",
+                       .cbs = {
+                               .cli_show = cli_show_isis_frr_lfa_priority_limit,
+                               .modify = isis_instance_fast_reroute_level_2_lfa_priority_limit_modify,
+                               .destroy = isis_instance_fast_reroute_level_2_lfa_priority_limit_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker",
+                       .cbs = {
+                               .cli_show = cli_show_isis_frr_lfa_tiebreaker,
+                               .create = isis_instance_fast_reroute_level_2_lfa_tiebreaker_create,
+                               .destroy = isis_instance_fast_reroute_level_2_lfa_tiebreaker_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker/type",
+                       .cbs = {
+                               .modify = isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/remote-lfa/prefix-list",
+                       .cbs = {
+                               .cli_show = cli_show_isis_frr_remote_lfa_plist,
+                               .modify = isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_modify,
+                               .destroy = isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-isisd:isis/instance/log-adjacency-changes",
                        .cbs = {
@@ -827,7 +925,35 @@ const struct frr_yang_module_info frr_isisd_info = {
                {
                        .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute",
                        .cbs = {
-                               .cli_show = cli_show_ip_isis_ti_lfa,
+                               .cli_show = cli_show_ip_isis_frr,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/lfa/enable",
+                       .cbs = {
+                               .modify = lib_interface_isis_fast_reroute_level_1_lfa_enable_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/lfa/exclude-interface",
+                       .cbs = {
+                               .cli_show = cli_show_frr_lfa_exclude_interface,
+                               .create = lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_create,
+                               .destroy = lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/remote-lfa/enable",
+                       .cbs = {
+                               .modify = lib_interface_isis_fast_reroute_level_1_remote_lfa_enable_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/remote-lfa/maximum-metric",
+                       .cbs = {
+                               .cli_show = cli_show_frr_remote_lfa_max_metric,
+                               .modify = lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_modify,
+                               .destroy = lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_destroy,
                        }
                },
                {
@@ -842,6 +968,34 @@ const struct frr_yang_module_info frr_isisd_info = {
                                .modify = lib_interface_isis_fast_reroute_level_1_ti_lfa_node_protection_modify,
                        }
                },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/lfa/enable",
+                       .cbs = {
+                               .modify = lib_interface_isis_fast_reroute_level_2_lfa_enable_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/lfa/exclude-interface",
+                       .cbs = {
+                               .cli_show = cli_show_frr_lfa_exclude_interface,
+                               .create = lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_create,
+                               .destroy = lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/remote-lfa/enable",
+                       .cbs = {
+                               .modify = lib_interface_isis_fast_reroute_level_2_remote_lfa_enable_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/remote-lfa/maximum-metric",
+                       .cbs = {
+                               .cli_show = cli_show_frr_remote_lfa_max_metric,
+                               .modify = lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_modify,
+                               .destroy = lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/ti-lfa/enable",
                        .cbs = {
index fb843131d9fe943ab6da24b679d4669b4500f235..679bc6345dd79b9c267713a11dc39c261564e2ab 100644 (file)
@@ -68,6 +68,18 @@ int isis_instance_spf_minimum_interval_level_1_modify(
        struct nb_cb_modify_args *args);
 int isis_instance_spf_minimum_interval_level_2_modify(
        struct nb_cb_modify_args *args);
+int isis_instance_spf_prefix_priorities_critical_access_list_name_modify(
+       struct nb_cb_modify_args *args);
+int isis_instance_spf_prefix_priorities_critical_access_list_name_destroy(
+       struct nb_cb_destroy_args *args);
+int isis_instance_spf_prefix_priorities_high_access_list_name_modify(
+       struct nb_cb_modify_args *args);
+int isis_instance_spf_prefix_priorities_high_access_list_name_destroy(
+       struct nb_cb_destroy_args *args);
+int isis_instance_spf_prefix_priorities_medium_access_list_name_modify(
+       struct nb_cb_modify_args *args);
+int isis_instance_spf_prefix_priorities_medium_access_list_name_destroy(
+       struct nb_cb_destroy_args *args);
 int isis_instance_area_password_create(struct nb_cb_create_args *args);
 int isis_instance_area_password_destroy(struct nb_cb_destroy_args *args);
 int isis_instance_area_password_password_modify(struct nb_cb_modify_args *args);
@@ -159,6 +171,38 @@ int isis_instance_multi_topology_ipv6_dstsrc_destroy(
        struct nb_cb_destroy_args *args);
 int isis_instance_multi_topology_ipv6_dstsrc_overload_modify(
        struct nb_cb_modify_args *args);
+int isis_instance_fast_reroute_level_1_lfa_load_sharing_modify(
+       struct nb_cb_modify_args *args);
+int isis_instance_fast_reroute_level_1_lfa_priority_limit_modify(
+       struct nb_cb_modify_args *args);
+int isis_instance_fast_reroute_level_1_lfa_priority_limit_destroy(
+       struct nb_cb_destroy_args *args);
+int isis_instance_fast_reroute_level_1_lfa_tiebreaker_create(
+       struct nb_cb_create_args *args);
+int isis_instance_fast_reroute_level_1_lfa_tiebreaker_destroy(
+       struct nb_cb_destroy_args *args);
+int isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify(
+       struct nb_cb_modify_args *args);
+int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_modify(
+       struct nb_cb_modify_args *args);
+int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_destroy(
+       struct nb_cb_destroy_args *args);
+int isis_instance_fast_reroute_level_2_lfa_load_sharing_modify(
+       struct nb_cb_modify_args *args);
+int isis_instance_fast_reroute_level_2_lfa_priority_limit_modify(
+       struct nb_cb_modify_args *args);
+int isis_instance_fast_reroute_level_2_lfa_priority_limit_destroy(
+       struct nb_cb_destroy_args *args);
+int isis_instance_fast_reroute_level_2_lfa_tiebreaker_create(
+       struct nb_cb_create_args *args);
+int isis_instance_fast_reroute_level_2_lfa_tiebreaker_destroy(
+       struct nb_cb_destroy_args *args);
+int isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify(
+       struct nb_cb_modify_args *args);
+int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_modify(
+       struct nb_cb_modify_args *args);
+int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_destroy(
+       struct nb_cb_destroy_args *args);
 int isis_instance_log_adjacency_changes_modify(struct nb_cb_modify_args *args);
 int isis_instance_mpls_te_create(struct nb_cb_create_args *args);
 int isis_instance_mpls_te_destroy(struct nb_cb_destroy_args *args);
@@ -258,10 +302,34 @@ int lib_interface_isis_multi_topology_ipv6_dstsrc_modify(
 int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args);
 int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args);
 int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args);
+int lib_interface_isis_fast_reroute_level_1_lfa_enable_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_create(
+       struct nb_cb_create_args *args);
+int lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_destroy(
+       struct nb_cb_destroy_args *args);
+int lib_interface_isis_fast_reroute_level_1_remote_lfa_enable_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_destroy(
+       struct nb_cb_destroy_args *args);
 int lib_interface_isis_fast_reroute_level_1_ti_lfa_enable_modify(
        struct nb_cb_modify_args *args);
 int lib_interface_isis_fast_reroute_level_1_ti_lfa_node_protection_modify(
        struct nb_cb_modify_args *args);
+int lib_interface_isis_fast_reroute_level_2_lfa_enable_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_create(
+       struct nb_cb_create_args *args);
+int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_destroy(
+       struct nb_cb_destroy_args *args);
+int lib_interface_isis_fast_reroute_level_2_remote_lfa_enable_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_destroy(
+       struct nb_cb_destroy_args *args);
 int lib_interface_isis_fast_reroute_level_2_ti_lfa_enable_modify(
        struct nb_cb_modify_args *args);
 int lib_interface_isis_fast_reroute_level_2_ti_lfa_node_protection_modify(
@@ -374,6 +442,8 @@ void cli_show_isis_spf_min_interval(struct vty *vty, struct lyd_node *dnode,
                                    bool show_defaults);
 void cli_show_isis_spf_ietf_backoff(struct vty *vty, struct lyd_node *dnode,
                                    bool show_defaults);
+void cli_show_isis_spf_prefix_priority(struct vty *vty, struct lyd_node *dnode,
+                                      bool show_defaults);
 void cli_show_isis_purge_origin(struct vty *vty, struct lyd_node *dnode,
                                bool show_defaults);
 void cli_show_isis_mpls_te(struct vty *vty, struct lyd_node *dnode,
@@ -410,6 +480,15 @@ void cli_show_isis_node_msd(struct vty *vty, struct lyd_node *dnode,
                            bool show_defaults);
 void cli_show_isis_prefix_sid(struct vty *vty, struct lyd_node *dnode,
                              bool show_defaults);
+void cli_show_isis_frr_lfa_priority_limit(struct vty *vty,
+                                         struct lyd_node *dnode,
+                                         bool show_defaults);
+void cli_show_isis_frr_lfa_tiebreaker(struct vty *vty, struct lyd_node *dnode,
+                                     bool show_defaults);
+void cli_show_isis_frr_lfa_load_sharing(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults);
+void cli_show_isis_frr_remote_lfa_plist(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults);
 void cli_show_ip_isis_passive(struct vty *vty, struct lyd_node *dnode,
                              bool show_defaults);
 void cli_show_ip_isis_password(struct vty *vty, struct lyd_node *dnode,
@@ -442,8 +521,12 @@ void cli_show_ip_isis_mt_ipv6_mgmt(struct vty *vty, struct lyd_node *dnode,
                                   bool show_defaults);
 void cli_show_ip_isis_mt_ipv6_dstsrc(struct vty *vty, struct lyd_node *dnode,
                                     bool show_defaults);
-void cli_show_ip_isis_ti_lfa(struct vty *vty, struct lyd_node *dnode,
-                            bool show_defaults);
+void cli_show_ip_isis_frr(struct vty *vty, struct lyd_node *dnode,
+                         bool show_defaults);
+void cli_show_frr_lfa_exclude_interface(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults);
+void cli_show_frr_remote_lfa_max_metric(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults);
 void cli_show_ip_isis_circ_type(struct vty *vty, struct lyd_node *dnode,
                                bool show_defaults);
 void cli_show_ip_isis_network_type(struct vty *vty, struct lyd_node *dnode,
index 45089410e9c5cc03f159f70519626417a072a9bf..ed0fea88249c846ec03ca87ceb23fa9abc1ff09b 100644 (file)
@@ -27,6 +27,8 @@
 #include "linklist.h"
 #include "log.h"
 #include "bfd.h"
+#include "filter.h"
+#include "plist.h"
 #include "spf_backoff.h"
 #include "lib_errors.h"
 #include "vrf.h"
@@ -50,6 +52,7 @@
 #include "isisd/isis_mt.h"
 #include "isisd/isis_redist.h"
 #include "isisd/isis_ldp_sync.h"
+#include "isisd/isis_dr.h"
 
 extern struct zclient *zclient;
 
@@ -212,6 +215,9 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args)
        uint8_t buff[255];
        struct isis_area *area;
        const char *net_title;
+       struct listnode *cnode;
+       struct isis_circuit *circuit;
+       int lvl;
 
        if (args->event != NB_EV_APPLY)
                return NB_OK;
@@ -235,6 +241,11 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args)
         * Last area address - reset the SystemID for this router
         */
        if (listcount(area->area_addrs) == 0) {
+               for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
+                       for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) {
+                               if (circuit->u.bc.is_dr[lvl - 1])
+                                       isis_dr_resign(circuit, lvl);
+                       }
                memset(area->isis->sysid, 0, ISIS_SYS_ID_LEN);
                area->isis->sysid_set = 0;
                if (IS_DEBUG_EVENTS)
@@ -625,6 +636,145 @@ int isis_instance_spf_minimum_interval_level_2_modify(
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-isisd:isis/instance/spf/prefix-priorities/critical/access-list-name
+ */
+int isis_instance_spf_prefix_priorities_critical_access_list_name_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       const char *acl_name;
+       struct spf_prefix_priority_acl *ppa;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       acl_name = yang_dnode_get_string(args->dnode, NULL);
+
+       ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_CRITICAL];
+       XFREE(MTYPE_ISIS_ACL_NAME, ppa->name);
+       ppa->name = XSTRDUP(MTYPE_ISIS_ACL_NAME, acl_name);
+       ppa->list_v4 = access_list_lookup(AFI_IP, acl_name);
+       ppa->list_v6 = access_list_lookup(AFI_IP6, acl_name);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int isis_instance_spf_prefix_priorities_critical_access_list_name_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct isis_area *area;
+       struct spf_prefix_priority_acl *ppa;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+
+       ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_CRITICAL];
+       XFREE(MTYPE_ISIS_ACL_NAME, ppa->name);
+       ppa->list_v4 = NULL;
+       ppa->list_v6 = NULL;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/spf/prefix-priorities/high/access-list-name
+ */
+int isis_instance_spf_prefix_priorities_high_access_list_name_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       const char *acl_name;
+       struct spf_prefix_priority_acl *ppa;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       acl_name = yang_dnode_get_string(args->dnode, NULL);
+
+       ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_HIGH];
+       XFREE(MTYPE_ISIS_ACL_NAME, ppa->name);
+       ppa->name = XSTRDUP(MTYPE_ISIS_ACL_NAME, acl_name);
+       ppa->list_v4 = access_list_lookup(AFI_IP, acl_name);
+       ppa->list_v6 = access_list_lookup(AFI_IP6, acl_name);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int isis_instance_spf_prefix_priorities_high_access_list_name_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct isis_area *area;
+       struct spf_prefix_priority_acl *ppa;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+
+       ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_HIGH];
+       XFREE(MTYPE_ISIS_ACL_NAME, ppa->name);
+       ppa->list_v4 = NULL;
+       ppa->list_v6 = NULL;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/spf/prefix-priorities/medium/access-list-name
+ */
+int isis_instance_spf_prefix_priorities_medium_access_list_name_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       const char *acl_name;
+       struct spf_prefix_priority_acl *ppa;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       acl_name = yang_dnode_get_string(args->dnode, NULL);
+
+       ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_MEDIUM];
+       XFREE(MTYPE_ISIS_ACL_NAME, ppa->name);
+       ppa->name = XSTRDUP(MTYPE_ISIS_ACL_NAME, acl_name);
+       ppa->list_v4 = access_list_lookup(AFI_IP, acl_name);
+       ppa->list_v6 = access_list_lookup(AFI_IP6, acl_name);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int isis_instance_spf_prefix_priorities_medium_access_list_name_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct isis_area *area;
+       struct spf_prefix_priority_acl *ppa;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+
+       ppa = &area->spf_prefix_priorities[SPF_PREFIX_PRIO_MEDIUM];
+       XFREE(MTYPE_ISIS_ACL_NAME, ppa->name);
+       ppa->list_v4 = NULL;
+       ppa->list_v6 = NULL;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
 /*
  * XPath: /frr-isisd:isis/instance/area-password
  */
@@ -1279,14 +1429,315 @@ int isis_instance_multi_topology_ipv6_dstsrc_destroy(
                                          "ipv6-dstsrc", false);
 }
 
-/*
- * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-dstsrc/overload
- */
-int isis_instance_multi_topology_ipv6_dstsrc_overload_modify(
-       struct nb_cb_modify_args *args)
+/*
+ * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-dstsrc/overload
+ */
+int isis_instance_multi_topology_ipv6_dstsrc_overload_modify(
+       struct nb_cb_modify_args *args)
+{
+       return isis_multi_topology_overload_common(args->event, args->dnode,
+                                                  "ipv6-dstsrc");
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/load-sharing
+ */
+int isis_instance_fast_reroute_level_1_lfa_load_sharing_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       area->lfa_load_sharing[0] = yang_dnode_get_bool(args->dnode, NULL);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/priority-limit
+ */
+int isis_instance_fast_reroute_level_1_lfa_priority_limit_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       area->lfa_priority_limit[0] = yang_dnode_get_enum(args->dnode, NULL);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int isis_instance_fast_reroute_level_1_lfa_priority_limit_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct isis_area *area;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       area->lfa_priority_limit[0] = SPF_PREFIX_PRIO_LOW;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker
+ */
+int isis_instance_fast_reroute_level_1_lfa_tiebreaker_create(
+       struct nb_cb_create_args *args)
+{
+       struct isis_area *area;
+       uint8_t index;
+       enum lfa_tiebreaker_type type;
+       struct lfa_tiebreaker *tie_b;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       index = yang_dnode_get_uint8(args->dnode, "./index");
+       type = yang_dnode_get_enum(args->dnode, "./type");
+
+       tie_b = isis_lfa_tiebreaker_add(area, ISIS_LEVEL1, index, type);
+       nb_running_set_entry(args->dnode, tie_b);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int isis_instance_fast_reroute_level_1_lfa_tiebreaker_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct lfa_tiebreaker *tie_b;
+       struct isis_area *area;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       tie_b = nb_running_unset_entry(args->dnode);
+       area = tie_b->area;
+       isis_lfa_tiebreaker_delete(area, ISIS_LEVEL1, tie_b);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker/type
+ */
+int isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct lfa_tiebreaker *tie_b;
+       struct isis_area *area;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       tie_b = nb_running_get_entry(args->dnode, NULL, true);
+       area = tie_b->area;
+       tie_b->type = yang_dnode_get_enum(args->dnode, NULL);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/remote-lfa/prefix-list
+ */
+int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       const char *plist_name;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       plist_name = yang_dnode_get_string(args->dnode, NULL);
+
+       area->rlfa_plist_name[0] = XSTRDUP(MTYPE_ISIS_PLIST_NAME, plist_name);
+       area->rlfa_plist[0] = prefix_list_lookup(AFI_IP, plist_name);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct isis_area *area;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+
+       XFREE(MTYPE_ISIS_PLIST_NAME, area->rlfa_plist_name[0]);
+       area->rlfa_plist[0] = NULL;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/load-sharing
+ */
+int isis_instance_fast_reroute_level_2_lfa_load_sharing_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       area->lfa_load_sharing[1] = yang_dnode_get_bool(args->dnode, NULL);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/priority-limit
+ */
+int isis_instance_fast_reroute_level_2_lfa_priority_limit_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       area->lfa_priority_limit[1] = yang_dnode_get_enum(args->dnode, NULL);
+
+       return NB_OK;
+}
+
+int isis_instance_fast_reroute_level_2_lfa_priority_limit_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct isis_area *area;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       area->lfa_priority_limit[1] = SPF_PREFIX_PRIO_LOW;
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker
+ */
+int isis_instance_fast_reroute_level_2_lfa_tiebreaker_create(
+       struct nb_cb_create_args *args)
+{
+       struct isis_area *area;
+       uint8_t index;
+       enum lfa_tiebreaker_type type;
+       struct lfa_tiebreaker *tie_b;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       index = yang_dnode_get_uint8(args->dnode, "./index");
+       type = yang_dnode_get_enum(args->dnode, "./type");
+
+       tie_b = isis_lfa_tiebreaker_add(area, ISIS_LEVEL2, index, type);
+       nb_running_set_entry(args->dnode, tie_b);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int isis_instance_fast_reroute_level_2_lfa_tiebreaker_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct lfa_tiebreaker *tie_b;
+       struct isis_area *area;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       tie_b = nb_running_unset_entry(args->dnode);
+       area = tie_b->area;
+       isis_lfa_tiebreaker_delete(area, ISIS_LEVEL2, tie_b);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker/type
+ */
+int isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct lfa_tiebreaker *tie_b;
+       struct isis_area *area;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       tie_b = nb_running_get_entry(args->dnode, NULL, true);
+       area = tie_b->area;
+       tie_b->type = yang_dnode_get_enum(args->dnode, NULL);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/remote-lfa/prefix-list
+ */
+int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       const char *plist_name;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       plist_name = yang_dnode_get_string(args->dnode, NULL);
+
+       area->rlfa_plist_name[1] = XSTRDUP(MTYPE_ISIS_PLIST_NAME, plist_name);
+       area->rlfa_plist[1] = prefix_list_lookup(AFI_IP, plist_name);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_destroy(
+       struct nb_cb_destroy_args *args)
 {
-       return isis_multi_topology_overload_common(args->event, args->dnode,
-                                                  "ipv6-dstsrc");
+       struct isis_area *area;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+
+       XFREE(MTYPE_ISIS_PLIST_NAME, area->rlfa_plist_name[1]);
+       area->rlfa_plist[1] = NULL;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
 }
 
 /*
@@ -1942,7 +2393,6 @@ int isis_instance_mpls_ldp_sync_create(struct nb_cb_create_args *args)
                /* register with opaque client to recv LDP-IGP Sync msgs */
                zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
                zclient_register_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
-               zclient_register_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE);
 
                if (!CHECK_FLAG(isis->ldp_sync_cmd.flags,
                                LDP_SYNC_FLAG_ENABLE)) {
@@ -3003,6 +3453,146 @@ int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args)
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/lfa/enable
+ */
+int lib_interface_isis_fast_reroute_level_1_lfa_enable_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       circuit->lfa_protection[0] = yang_dnode_get_bool(args->dnode, NULL);
+       if (circuit->lfa_protection[0])
+               circuit->area->lfa_protected_links[0]++;
+       else {
+               assert(circuit->area->lfa_protected_links[0] > 0);
+               circuit->area->lfa_protected_links[0]--;
+       }
+
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/lfa/exclude-interface
+ */
+int lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_create(
+       struct nb_cb_create_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+       const char *exclude_ifname;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       exclude_ifname = yang_dnode_get_string(args->dnode, NULL);
+
+       isis_lfa_excluded_iface_add(circuit, ISIS_LEVEL1, exclude_ifname);
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+       const char *exclude_ifname;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       exclude_ifname = yang_dnode_get_string(args->dnode, NULL);
+
+       isis_lfa_excluded_iface_delete(circuit, ISIS_LEVEL1, exclude_ifname);
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/remote-lfa/enable
+ */
+int lib_interface_isis_fast_reroute_level_1_remote_lfa_enable_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       circuit->rlfa_protection[0] = yang_dnode_get_bool(args->dnode, NULL);
+       if (circuit->rlfa_protection[0])
+               circuit->area->rlfa_protected_links[0]++;
+       else {
+               assert(circuit->area->rlfa_protected_links[0] > 0);
+               circuit->area->rlfa_protected_links[0]--;
+       }
+
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/remote-lfa/maximum-metric
+ */
+int lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       circuit->rlfa_max_metric[0] = yang_dnode_get_uint32(args->dnode, NULL);
+
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       circuit->rlfa_max_metric[0] = 0;
+
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
 /*
  * XPath:
  * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/ti-lfa/enable
@@ -3019,10 +3609,10 @@ int lib_interface_isis_fast_reroute_level_1_ti_lfa_enable_modify(
        circuit = nb_running_get_entry(args->dnode, NULL, true);
        circuit->tilfa_protection[0] = yang_dnode_get_bool(args->dnode, NULL);
        if (circuit->tilfa_protection[0])
-               circuit->area->lfa_protected_links[0]++;
+               circuit->area->tilfa_protected_links[0]++;
        else {
-               assert(circuit->area->lfa_protected_links[0] > 0);
-               circuit->area->lfa_protected_links[0]--;
+               assert(circuit->area->tilfa_protected_links[0] > 0);
+               circuit->area->tilfa_protected_links[0]--;
        }
 
        area = circuit->area;
@@ -3054,6 +3644,146 @@ int lib_interface_isis_fast_reroute_level_1_ti_lfa_node_protection_modify(
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/lfa/enable
+ */
+int lib_interface_isis_fast_reroute_level_2_lfa_enable_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       circuit->lfa_protection[1] = yang_dnode_get_bool(args->dnode, NULL);
+       if (circuit->lfa_protection[1])
+               circuit->area->lfa_protected_links[1]++;
+       else {
+               assert(circuit->area->lfa_protected_links[1] > 0);
+               circuit->area->lfa_protected_links[1]--;
+       }
+
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/lfa/exclude-interface
+ */
+int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_create(
+       struct nb_cb_create_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+       const char *exclude_ifname;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       exclude_ifname = yang_dnode_get_string(args->dnode, NULL);
+
+       isis_lfa_excluded_iface_add(circuit, ISIS_LEVEL2, exclude_ifname);
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+       const char *exclude_ifname;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       exclude_ifname = yang_dnode_get_string(args->dnode, NULL);
+
+       isis_lfa_excluded_iface_delete(circuit, ISIS_LEVEL2, exclude_ifname);
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/remote-lfa/enable
+ */
+int lib_interface_isis_fast_reroute_level_2_remote_lfa_enable_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       circuit->rlfa_protection[1] = yang_dnode_get_bool(args->dnode, NULL);
+       if (circuit->rlfa_protection[1])
+               circuit->area->rlfa_protected_links[1]++;
+       else {
+               assert(circuit->area->rlfa_protected_links[1] > 0);
+               circuit->area->rlfa_protected_links[1]--;
+       }
+
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/remote-lfa/maximum-metric
+ */
+int lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       circuit->rlfa_max_metric[1] = yang_dnode_get_uint32(args->dnode, NULL);
+
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       circuit->rlfa_max_metric[1] = 0;
+
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
 /*
  * XPath:
  * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/ti-lfa/enable
@@ -3070,10 +3800,10 @@ int lib_interface_isis_fast_reroute_level_2_ti_lfa_enable_modify(
        circuit = nb_running_get_entry(args->dnode, NULL, true);
        circuit->tilfa_protection[1] = yang_dnode_get_bool(args->dnode, NULL);
        if (circuit->tilfa_protection[1])
-               circuit->area->lfa_protected_links[1]++;
+               circuit->area->tilfa_protected_links[1]++;
        else {
-               assert(circuit->area->lfa_protected_links[1] > 0);
-               circuit->area->lfa_protected_links[1]--;
+               assert(circuit->area->tilfa_protected_links[1] > 0);
+               circuit->area->tilfa_protected_links[1]--;
        }
 
        area = circuit->area;
index d664a6f8962545c55eb25ed384b57d8137140c44..e1baf351f49952a22bad9fb68624c59a91e4784b 100644 (file)
@@ -183,7 +183,7 @@ static void isis_route_add_dummy_nexthops(struct isis_route_info *rinfo,
 static struct isis_route_info *
 isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p,
                    uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
-                   struct list *adjacencies)
+                   struct list *adjacencies, bool allow_ecmp)
 {
        struct isis_route_info *rinfo;
        struct isis_vertex_adj *vadj;
@@ -205,6 +205,8 @@ isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p,
                if (CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) {
                        isis_route_add_dummy_nexthops(rinfo, sadj->id, sr,
                                                      label_stack);
+                       if (!allow_ecmp)
+                               break;
                        continue;
                }
 
@@ -233,6 +235,8 @@ isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p,
                }
                adjinfo2nexthop(prefix->family, rinfo->nexthops, adj, sr,
                                label_stack);
+               if (!allow_ecmp)
+                       break;
        }
 
        rinfo->cost = cost;
@@ -275,6 +279,22 @@ static bool isis_sr_psid_info_same(struct isis_sr_psid_info *new,
        return true;
 }
 
+static bool isis_label_stack_same(struct mpls_label_stack *new,
+                                 struct mpls_label_stack *old)
+{
+       if (!new && !old)
+               return true;
+       if (!new || !old)
+               return false;
+       if (new->num_labels != old->num_labels)
+               return false;
+       if (memcmp(&new->label, &old->label,
+                  sizeof(mpls_label_t) * new->num_labels))
+               return false;
+
+       return true;
+}
+
 static int isis_route_info_same(struct isis_route_info *new,
                                struct isis_route_info *old, char *buf,
                                size_t buf_size)
@@ -323,6 +343,12 @@ static int isis_route_info_same(struct isis_route_info *new,
                                snprintf(buf, buf_size, "nhop SR label");
                        return 0;
                }
+               if (!isis_label_stack_same(new_nh->label_stack,
+                                          old_nh->label_stack)) {
+                       if (buf)
+                               snprintf(buf, buf_size, "nhop label stack");
+                       return 0;
+               }
        }
 
        /* only the resync flag needs to be checked */
@@ -339,8 +365,8 @@ static int isis_route_info_same(struct isis_route_info *new,
 struct isis_route_info *
 isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
                  uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
-                 struct list *adjacencies, struct isis_area *area,
-                 struct route_table *table)
+                 struct list *adjacencies, bool allow_ecmp,
+                 struct isis_area *area, struct route_table *table)
 {
        struct route_node *route_node;
        struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
@@ -350,7 +376,7 @@ isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
                return NULL;
 
        rinfo_new = isis_route_info_new(prefix, src_p, cost, depth, sr,
-                                       adjacencies);
+                                       adjacencies, allow_ecmp);
        route_node = srcdest_rnode_get(table, prefix, src_p);
 
        rinfo_old = route_node->info;
@@ -396,8 +422,8 @@ isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
        return route_info;
 }
 
-static void isis_route_delete(struct isis_area *area, struct route_node *rode,
-                             struct route_table *table)
+void isis_route_delete(struct isis_area *area, struct route_node *rode,
+                      struct route_table *table)
 {
        struct isis_route_info *rinfo;
        char buff[SRCDEST2STR_BUFFER];
@@ -462,9 +488,6 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix,
                SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
                UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
        } else {
-               if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
-                       return;
-
                /* Uninstall Prefix-SID label. */
                if (route_info->sr.present)
                        isis_zebra_prefix_sid_uninstall(
@@ -512,6 +535,10 @@ static void _isis_route_verify_table(struct isis_area *area,
                                rinfo->backup = rnode_bck->info;
                                UNSET_FLAG(rinfo->flag,
                                           ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+                       } else if (rinfo->backup) {
+                               rinfo->backup = NULL;
+                               UNSET_FLAG(rinfo->flag,
+                                          ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
                        }
                }
 
@@ -625,6 +652,10 @@ void isis_route_verify_merge(struct isis_area *area,
                                rinfo->backup = rnode_bck->info;
                                UNSET_FLAG(rinfo->flag,
                                           ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+                       } else if (rinfo->backup) {
+                               rinfo->backup = NULL;
+                               UNSET_FLAG(rinfo->flag,
+                                          ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
                        }
 
                        mrnode = srcdest_rnode_get(merge, prefix, src_p);
index b5e4aed6cccbe6df6e968d5dc8a8ceeee4df2445..d6763ec76c10e267ac3494aed32930eeae7b9e31 100644 (file)
@@ -61,8 +61,10 @@ void adjinfo2nexthop(int family, struct list *nexthops,
 struct isis_route_info *
 isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
                  uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
-                 struct list *adjacencies, struct isis_area *area,
-                 struct route_table *table);
+                 struct list *adjacencies, bool allow_ecmp,
+                 struct isis_area *area, struct route_table *table);
+void isis_route_delete(struct isis_area *area, struct route_node *rode,
+                      struct route_table *table);
 
 /* Walk the given table and install new routes to zebra and remove old ones.
  * route status is tracked using ISIS_ROUTE_FLAG_ACTIVE */
index 19cacde4fe29ca64ac1a42d19da0f544f7d0e2ca..dee082fce1e9df4fb13c8bb8031092aef2f82ce0 100644 (file)
@@ -32,6 +32,7 @@
 #include "termtable.h"
 #include "memory.h"
 #include "prefix.h"
+#include "filter.h"
 #include "if.h"
 #include "hash.h"
 #include "table.h"
@@ -55,6 +56,7 @@
 #include "isis_csm.h"
 #include "isis_mt.h"
 #include "isis_tlvs.h"
+#include "isis_zebra.h"
 #include "fabricd.h"
 #include "isis_spf_private.h"
 
@@ -216,7 +218,7 @@ struct isis_vertex *isis_spf_prefix_sid_lookup(struct isis_spftree *spftree,
        return hash_lookup(spftree->prefix_sids, &lookup);
 }
 
-static void isis_vertex_adj_free(void *arg)
+void isis_vertex_adj_free(void *arg)
 {
        struct isis_vertex_adj *vadj = arg;
 
@@ -246,10 +248,10 @@ static struct isis_vertex *isis_vertex_new(struct isis_spftree *spftree,
        return vertex;
 }
 
-static struct isis_vertex_adj *isis_vertex_adj_add(struct isis_spftree *spftree,
-                                                  struct isis_vertex *vertex,
-                                                  struct isis_spf_adj *sadj,
-                                                  struct isis_prefix_sid *psid)
+struct isis_vertex_adj *
+isis_vertex_adj_add(struct isis_spftree *spftree, struct isis_vertex *vertex,
+                   struct list *vadj_list, struct isis_spf_adj *sadj,
+                   struct isis_prefix_sid *psid, bool last_hop)
 {
        struct isis_vertex_adj *vadj;
 
@@ -262,9 +264,6 @@ static struct isis_vertex_adj *isis_vertex_adj_add(struct isis_spftree *spftree,
                                "ISIS-SPF: ignoring different Prefix-SID for route %pFX",
                                &vertex->N.ip.p.dest);
                else {
-                       bool last_hop;
-
-                       last_hop = (vertex->depth == 2);
                        vadj->sr.sid = *psid;
                        vadj->sr.label = sr_prefix_out_label(
                                spftree->lspdb, vertex->N.ip.p.dest.family,
@@ -273,7 +272,7 @@ static struct isis_vertex_adj *isis_vertex_adj_add(struct isis_spftree *spftree,
                                vadj->sr.present = true;
                }
        }
-       listnode_add(vertex->Adj_N, vadj);
+       listnode_add(vadj_list, vadj);
 
        return vadj;
 }
@@ -356,7 +355,10 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area,
        tree->tree_id = tree_id;
        tree->family = (tree->tree_id == SPFTREE_IPV4) ? AF_INET : AF_INET6;
        tree->flags = flags;
-       if (tree->type == SPF_TYPE_TI_LFA) {
+       isis_rlfa_list_init(tree);
+       tree->lfa.remote.pc_spftrees = list_new();
+       tree->lfa.remote.pc_spftrees->del = (void (*)(void *))isis_spftree_del;
+       if (tree->type == SPF_TYPE_RLFA || tree->type == SPF_TYPE_TI_LFA) {
                isis_spf_node_list_init(&tree->lfa.p_space);
                isis_spf_node_list_init(&tree->lfa.q_space);
        }
@@ -368,7 +370,11 @@ void isis_spftree_del(struct isis_spftree *spftree)
 {
        hash_clean(spftree->prefix_sids, NULL);
        hash_free(spftree->prefix_sids);
-       if (spftree->type == SPF_TYPE_TI_LFA) {
+       isis_zebra_rlfa_unregister_all(spftree);
+       isis_rlfa_list_clear(spftree);
+       list_delete(&spftree->lfa.remote.pc_spftrees);
+       if (spftree->type == SPF_TYPE_RLFA
+           || spftree->type == SPF_TYPE_TI_LFA) {
                isis_spf_node_list_clear(&spftree->lfa.q_space);
                isis_spf_node_list_clear(&spftree->lfa.p_space);
        }
@@ -528,6 +534,7 @@ isis_spf_add2tent(struct isis_spftree *spftree, enum vertextype vtype, void *id,
 {
        struct isis_vertex *vertex;
        struct listnode *node;
+       bool last_hop;
        char buff[VID2STR_BUFFER];
 
        vertex = isis_find_vertex(&spftree->paths, id, vtype);
@@ -593,14 +600,16 @@ isis_spf_add2tent(struct isis_spftree *spftree, enum vertextype vtype, void *id,
        if (CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC))
                vertex_update_firsthops(vertex, parent);
 
+       last_hop = (vertex->depth == 2);
        if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) {
                struct isis_vertex_adj *parent_vadj;
 
                for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node, parent_vadj))
-                       isis_vertex_adj_add(spftree, vertex, parent_vadj->sadj,
-                                           psid);
+                       isis_vertex_adj_add(spftree, vertex, vertex->Adj_N,
+                                           parent_vadj->sadj, psid, last_hop);
        } else if (sadj) {
-               isis_vertex_adj_add(spftree, vertex, sadj, psid);
+               isis_vertex_adj_add(spftree, vertex, vertex->Adj_N, sadj, psid,
+                                   last_hop);
        }
 
 #ifdef EXTREME_DEBUG
@@ -628,9 +637,13 @@ static void isis_spf_add_local(struct isis_spftree *spftree,
        if (vertex) {
                /* C.2.5   c) */
                if (vertex->d_N == cost) {
-                       if (sadj)
-                               isis_vertex_adj_add(spftree, vertex, sadj,
-                                                   psid);
+                       if (sadj) {
+                               bool last_hop = (vertex->depth == 2);
+
+                               isis_vertex_adj_add(spftree, vertex,
+                                                   vertex->Adj_N, sadj, psid,
+                                                   last_hop);
+                       }
                        /*       d) */
                        if (!CHECK_FLAG(spftree->flags,
                                        F_SPFTREE_NO_ADJACENCIES)
@@ -718,11 +731,16 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
                        struct isis_vertex_adj *parent_vadj;
                        for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node,
                                                  parent_vadj))
-                               if (!isis_vertex_adj_exists(spftree, vertex,
-                                                           parent_vadj->sadj))
+                               if (!isis_vertex_adj_exists(
+                                           spftree, vertex,
+                                           parent_vadj->sadj)) {
+                                       bool last_hop = (vertex->depth == 2);
+
                                        isis_vertex_adj_add(spftree, vertex,
+                                                           vertex->Adj_N,
                                                            parent_vadj->sadj,
-                                                           psid);
+                                                           psid, last_hop);
+                               }
                        if (CHECK_FLAG(spftree->flags,
                                       F_SPFTREE_HOPCOUNT_METRIC))
                                vertex_update_firsthops(vertex, parent);
@@ -771,7 +789,7 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree,
        bool has_valid_psid;
 
        if (isis_lfa_excise_node_check(spftree, lsp->hdr.lsp_id)) {
-               if (IS_DEBUG_TILFA)
+               if (IS_DEBUG_LFA)
                        zlog_debug("ISIS-LFA: excising node %s",
                                   print_sys_hostname(lsp->hdr.lsp_id));
                return ISIS_OK;
@@ -810,7 +828,8 @@ lspfragloop:
 #endif /* EXTREME_DEBUG */
 
        if (no_overload) {
-               if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) {
+               if ((pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
+                   && spftree->area->oldmetric) {
                        struct isis_oldstyle_reach *r;
                        for (r = (struct isis_oldstyle_reach *)
                                         lsp->tlvs->oldstyle_reach.head;
@@ -838,42 +857,47 @@ lspfragloop:
                        }
                }
 
-               struct isis_item_list *te_neighs = NULL;
-               if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
-                       te_neighs = &lsp->tlvs->extended_reach;
-               else
-                       te_neighs = isis_lookup_mt_items(&lsp->tlvs->mt_reach,
-                                                        spftree->mtid);
-
-               struct isis_extended_reach *er;
-               for (er = te_neighs
-                                 ? (struct isis_extended_reach *)
-                                           te_neighs->head
-                                 : NULL;
-                    er; er = er->next) {
-                       /* C.2.6 a) */
-                       /* Two way connectivity */
-                       if (!LSP_PSEUDO_ID(er->id)
-                           && !memcmp(er->id, root_sysid, ISIS_SYS_ID_LEN))
-                               continue;
-                       if (!pseudo_lsp
-                           && !memcmp(er->id, null_sysid, ISIS_SYS_ID_LEN))
-                               continue;
-                       dist = cost
-                              + (CHECK_FLAG(spftree->flags,
-                                            F_SPFTREE_HOPCOUNT_METRIC)
-                                         ? 1
-                                         : er->metric);
-                       process_N(spftree,
-                                 LSP_PSEUDO_ID(er->id) ? VTYPE_PSEUDO_TE_IS
-                                                       : VTYPE_NONPSEUDO_TE_IS,
-                                 (void *)er->id, dist, depth + 1, NULL,
-                                 parent);
+               if (spftree->area->newmetric) {
+                       struct isis_item_list *te_neighs = NULL;
+                       if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
+                               te_neighs = &lsp->tlvs->extended_reach;
+                       else
+                               te_neighs = isis_lookup_mt_items(
+                                       &lsp->tlvs->mt_reach, spftree->mtid);
+
+                       struct isis_extended_reach *er;
+                       for (er = te_neighs ? (struct isis_extended_reach *)
+                                                     te_neighs->head
+                                           : NULL;
+                            er; er = er->next) {
+                               /* C.2.6 a) */
+                               /* Two way connectivity */
+                               if (!LSP_PSEUDO_ID(er->id)
+                                   && !memcmp(er->id, root_sysid,
+                                              ISIS_SYS_ID_LEN))
+                                       continue;
+                               if (!pseudo_lsp
+                                   && !memcmp(er->id, null_sysid,
+                                              ISIS_SYS_ID_LEN))
+                                       continue;
+                               dist = cost
+                                      + (CHECK_FLAG(spftree->flags,
+                                                    F_SPFTREE_HOPCOUNT_METRIC)
+                                                 ? 1
+                                                 : er->metric);
+                               process_N(spftree,
+                                         LSP_PSEUDO_ID(er->id)
+                                                 ? VTYPE_PSEUDO_TE_IS
+                                                 : VTYPE_NONPSEUDO_TE_IS,
+                                         (void *)er->id, dist, depth + 1, NULL,
+                                         parent);
+                       }
                }
        }
 
        if (!fabricd && !pseudo_lsp && spftree->family == AF_INET
-           && spftree->mtid == ISIS_MT_IPV4_UNICAST) {
+           && spftree->mtid == ISIS_MT_IPV4_UNICAST
+           && spftree->area->oldmetric) {
                struct isis_item_list *reachs[] = {
                        &lsp->tlvs->oldstyle_ip_reach,
                        &lsp->tlvs->oldstyle_ip_reach_ext};
@@ -898,6 +922,10 @@ lspfragloop:
                }
        }
 
+       /* we can skip all the rest if we're using metric style narrow */
+       if (!spftree->area->newmetric)
+               goto end;
+
        if (!pseudo_lsp && spftree->family == AF_INET) {
                struct isis_item_list *ipv4_reachs;
                if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
@@ -1017,6 +1045,7 @@ lspfragloop:
                }
        }
 
+end:
        if (fragnode == NULL)
                fragnode = listhead(lsp->lspu.frags);
        else
@@ -1140,7 +1169,7 @@ static void isis_spf_preload_tent(struct isis_spftree *spftree,
                        adj_id = sadj->id;
 
                if (isis_lfa_excise_adj_check(spftree, adj_id)) {
-                       if (IS_DEBUG_TILFA)
+                       if (IS_DEBUG_LFA)
                                zlog_debug("ISIS-SPF: excising adjacency %s",
                                           isis_format_id(sadj->id,
                                                          ISIS_SYS_ID_LEN + 1));
@@ -1158,9 +1187,9 @@ static void isis_spf_preload_tent(struct isis_spftree *spftree,
                                                   : VTYPE_NONPSEUDO_TE_IS,
                                           sadj->id, sadj, metric, NULL,
                                           parent);
-               } else if (sadj->lan.lsp_pseudo) {
-                       isis_spf_process_lsp(spftree, sadj->lan.lsp_pseudo,
-                                            metric, 0, spftree->sysid, parent);
+               } else if (sadj->lsp) {
+                       isis_spf_process_lsp(spftree, sadj->lsp, metric, 0,
+                                            spftree->sysid, parent);
                }
        }
 }
@@ -1243,12 +1272,24 @@ static void spf_adj_list_parse_tlv(struct isis_spftree *spftree,
                                   struct isis_ext_subtlvs *subtlvs)
 {
        struct isis_spf_adj *sadj;
+       uint8_t lspid[ISIS_SYS_ID_LEN + 2];
+       struct isis_lsp *lsp;
        uint8_t flags = 0;
 
        /* Skip self in the pseudonode. */
        if (desig_is_id && !memcmp(id, spftree->sysid, ISIS_SYS_ID_LEN))
                return;
 
+       /* Find LSP from the adjacency. */
+       memcpy(lspid, id, ISIS_SYS_ID_LEN + 1);
+       LSP_FRAGMENT(lspid) = 0;
+       lsp = lsp_search(spftree->lspdb, lspid);
+       if (lsp == NULL || lsp->hdr.rem_lifetime == 0) {
+               zlog_warn("ISIS-SPF: No LSP found from root to L%d %s",
+                         spftree->level, rawlspid_print(lspid));
+               return;
+       }
+
        sadj = XCALLOC(MTYPE_ISIS_SPF_ADJ, sizeof(*sadj));
        memcpy(sadj->id, id, sizeof(sadj->id));
        if (desig_is_id) {
@@ -1260,9 +1301,14 @@ static void spf_adj_list_parse_tlv(struct isis_spftree *spftree,
                sadj->metric = metric;
        if (oldmetric)
                SET_FLAG(flags, F_ISIS_SPF_ADJ_OLDMETRIC);
+       sadj->lsp = lsp;
        sadj->subtlvs = subtlvs;
        sadj->flags = flags;
 
+       if ((oldmetric && metric == ISIS_NARROW_METRIC_INFINITY)
+           || (!oldmetric && metric == ISIS_WIDE_METRIC_INFINITY))
+               SET_FLAG(flags, F_ISIS_SPF_ADJ_METRIC_INFINITY);
+
        /* Set real adjacency. */
        if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES)
            && !LSP_PSEUDO_ID(id)) {
@@ -1294,24 +1340,8 @@ static void spf_adj_list_parse_tlv(struct isis_spftree *spftree,
        }
 
        /* Parse pseudonode LSP too. */
-       if (LSP_PSEUDO_ID(id)) {
-               uint8_t lspid[ISIS_SYS_ID_LEN + 2];
-               struct isis_lsp *lsp_pseudo;
-
-               memcpy(lspid, id, ISIS_SYS_ID_LEN + 1);
-               LSP_FRAGMENT(lspid) = 0;
-               lsp_pseudo = lsp_search(spftree->lspdb, lspid);
-               if (lsp_pseudo == NULL || lsp_pseudo->hdr.rem_lifetime == 0) {
-                       zlog_warn(
-                               "ISIS-SPF: No LSP found from root to L%d DR %s",
-                               spftree->level, rawlspid_print(id));
-                       return;
-               }
-
-               sadj->lan.lsp_pseudo = lsp_pseudo;
-               spf_adj_list_parse_lsp(spftree, adj_list, lsp_pseudo, id,
-                                      metric);
-       }
+       if (LSP_PSEUDO_ID(id))
+               spf_adj_list_parse_lsp(spftree, adj_list, lsp, id, metric);
 }
 
 static void spf_adj_list_parse_lsp(struct isis_spftree *spftree,
@@ -1418,32 +1448,68 @@ static void init_spt(struct isis_spftree *spftree, int mtid)
        list_delete_all_node(spftree->sadj_list);
        isis_vertex_queue_clear(&spftree->tents);
        isis_vertex_queue_clear(&spftree->paths);
+       isis_zebra_rlfa_unregister_all(spftree);
+       isis_rlfa_list_clear(spftree);
+       list_delete_all_node(spftree->lfa.remote.pc_spftrees);
+       memset(&spftree->lfa.protection_counters, 0,
+              sizeof(spftree->lfa.protection_counters));
 
        spftree->mtid = mtid;
 }
 
+static enum spf_prefix_priority
+spf_prefix_priority(struct isis_spftree *spftree, struct isis_vertex *vertex)
+{
+       struct isis_area *area = spftree->area;
+       struct prefix *prefix = &vertex->N.ip.p.dest;
+
+       for (int priority = SPF_PREFIX_PRIO_CRITICAL;
+            priority <= SPF_PREFIX_PRIO_MEDIUM; priority++) {
+               struct spf_prefix_priority_acl *ppa;
+               enum filter_type ret = FILTER_PERMIT;
+
+               ppa = &area->spf_prefix_priorities[priority];
+               switch (spftree->family) {
+               case AF_INET:
+                       ret = access_list_apply(ppa->list_v4, prefix);
+                       break;
+               case AF_INET6:
+                       ret = access_list_apply(ppa->list_v6, prefix);
+                       break;
+               default:
+                       break;
+               }
+
+               if (ret == FILTER_PERMIT)
+                       return priority;
+       }
+
+       /* Assign medium priority to loopback prefixes by default. */
+       if (is_host_route(prefix))
+               return SPF_PREFIX_PRIO_MEDIUM;
+
+       return SPF_PREFIX_PRIO_LOW;
+}
+
 static void spf_path_process(struct isis_spftree *spftree,
                             struct isis_vertex *vertex)
 {
        struct isis_area *area = spftree->area;
+       int level = spftree->level;
        char buff[VID2STR_BUFFER];
 
-       if (VTYPE_IS(vertex->type)
+       if (spftree->type == SPF_TYPE_TI_LFA && VTYPE_IS(vertex->type)
            && !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES)) {
                if (listcount(vertex->Adj_N) > 0) {
-                       if (spftree->type == SPF_TYPE_TI_LFA) {
-                               struct isis_adjacency *adj;
+                       struct isis_adjacency *adj;
 
-                               if (isis_lfa_check(spftree, vertex) != 0)
-                                       return;
+                       if (isis_tilfa_check(spftree, vertex) != 0)
+                               return;
 
-                               adj = isis_adj_find(area, spftree->level,
-                                                   vertex->N.id);
-                               if (adj)
-                                       sr_adj_sid_add_single(
-                                               adj, spftree->family, true,
-                                               vertex->Adj_N);
-                       }
+                       adj = isis_adj_find(area, level, vertex->N.id);
+                       if (adj)
+                               sr_adj_sid_add_single(adj, spftree->family,
+                                                     true, vertex->Adj_N);
                } else if (IS_DEBUG_SPF_EVENTS)
                        zlog_debug(
                                "ISIS-SPF: no adjacencies, do not install backup Adj-SID for %s depth %d dist %d",
@@ -1453,21 +1519,71 @@ static void spf_path_process(struct isis_spftree *spftree,
 
        if (VTYPE_IP(vertex->type)
            && !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ROUTES)) {
+               enum spf_prefix_priority priority;
+
+               priority = spf_prefix_priority(spftree, vertex);
+               vertex->N.ip.priority = priority;
                if (vertex->depth == 1 || listcount(vertex->Adj_N) > 0) {
+                       struct isis_spftree *pre_spftree;
                        struct route_table *route_table;
+                       bool allow_ecmp;
+
+                       switch (spftree->type) {
+                       case SPF_TYPE_RLFA:
+                       case SPF_TYPE_TI_LFA:
+                               if (priority
+                                   > area->lfa_priority_limit[level - 1]) {
+                                       if (IS_DEBUG_LFA)
+                                               zlog_debug(
+                                                       "ISIS-LFA: skipping %s %s (low prefix priority)",
+                                                       vtype2string(
+                                                               vertex->type),
+                                                       vid2string(
+                                                               vertex, buff,
+                                                               sizeof(buff)));
+                                       return;
+                               }
+                               break;
+                       default:
+                               break;
+                       }
 
-                       if (spftree->type == SPF_TYPE_TI_LFA) {
-                               if (isis_lfa_check(spftree, vertex) != 0)
+                       switch (spftree->type) {
+                       case SPF_TYPE_RLFA:
+                               isis_rlfa_check(spftree, vertex);
+                               return;
+                       case SPF_TYPE_TI_LFA:
+                               if (isis_tilfa_check(spftree, vertex) != 0)
                                        return;
-                               route_table = spftree->lfa.old.spftree
-                                                     ->route_table_backup;
-                       } else
+
+                               pre_spftree = spftree->lfa.old.spftree;
+                               route_table = pre_spftree->route_table_backup;
+                               allow_ecmp = area->lfa_load_sharing[level - 1];
+                               pre_spftree->lfa.protection_counters
+                                       .tilfa[vertex->N.ip.priority] += 1;
+                               break;
+                       default:
                                route_table = spftree->route_table;
+                               allow_ecmp = true;
+
+                               /*
+                                * Update LFA protection counters (ignore local
+                                * routes).
+                                */
+                               if (vertex->depth > 1) {
+                                       spftree->lfa.protection_counters
+                                               .total[priority] += 1;
+                                       if (listcount(vertex->Adj_N) > 1)
+                                               spftree->lfa.protection_counters
+                                                       .ecmp[priority] += 1;
+                               }
+                               break;
+                       }
 
-                       isis_route_create(&vertex->N.ip.p.dest,
-                                         &vertex->N.ip.p.src, vertex->d_N,
-                                         vertex->depth, &vertex->N.ip.sr,
-                                         vertex->Adj_N, area, route_table);
+                       isis_route_create(
+                               &vertex->N.ip.p.dest, &vertex->N.ip.p.src,
+                               vertex->d_N, vertex->depth, &vertex->N.ip.sr,
+                               vertex->Adj_N, allow_ecmp, area, route_table);
                } else if (IS_DEBUG_SPF_EVENTS)
                        zlog_debug(
                                "ISIS-SPF: no adjacencies, do not install route for %s depth %d dist %d",
@@ -1641,7 +1757,8 @@ static void isis_run_spf_with_protection(struct isis_area *area,
        isis_run_spf(spftree);
 
        /* Run LFA protection if configured. */
-       if (area->lfa_protected_links[spftree->level - 1] > 0)
+       if (area->lfa_protected_links[spftree->level - 1] > 0
+           || area->tilfa_protected_links[spftree->level - 1] > 0)
                isis_spf_run_lfa(area, spftree);
 }
 
@@ -1751,6 +1868,7 @@ int _isis_spf_schedule(struct isis_area *area, int level,
                        area->area_tag, level, diff, func, file, line);
        }
 
+       thread_cancel(&area->t_rlfa_rib_update);
        if (area->spf_delay_ietf[level - 1]) {
                /* Need to call schedule function also if spf delay is running
                 * to
@@ -1811,7 +1929,8 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
                "Vertex               Type         Metric Next-Hop             Interface Parent\n");
 
        for (ALL_QUEUE_ELEMENTS_RO(queue, node, vertex)) {
-               if (memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) {
+               if (VTYPE_IS(vertex->type)
+                   && memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) {
                        vty_out(vty, "%-20s %-12s %-6s",
                                print_sys_hostname(root_sysid), "", "");
                        vty_out(vty, "%-30s\n", "");
@@ -2280,10 +2399,223 @@ DEFUN(show_isis_route, show_isis_route_cmd,
        return CMD_SUCCESS;
 }
 
+static void isis_print_frr_summary_line(struct ttable *tt,
+                                       const char *protection,
+                                       uint32_t counters[SPF_PREFIX_PRIO_MAX])
+{
+       uint32_t critical, high, medium, low, total;
+
+       critical = counters[SPF_PREFIX_PRIO_CRITICAL];
+       high = counters[SPF_PREFIX_PRIO_HIGH];
+       medium = counters[SPF_PREFIX_PRIO_MEDIUM];
+       low = counters[SPF_PREFIX_PRIO_LOW];
+       total = critical + high + medium + low;
+
+       ttable_add_row(tt, "%s|%u|%u|%u|%u|%u", protection, critical, high,
+                      medium, low, total);
+}
+
+static void
+isis_print_frr_summary_line_coverage(struct ttable *tt, const char *protection,
+                                    double counters[SPF_PREFIX_PRIO_MAX],
+                                    double total)
+{
+       double critical, high, medium, low;
+
+       critical = counters[SPF_PREFIX_PRIO_CRITICAL] * 100;
+       high = counters[SPF_PREFIX_PRIO_HIGH] * 100;
+       medium = counters[SPF_PREFIX_PRIO_MEDIUM] * 100;
+       low = counters[SPF_PREFIX_PRIO_LOW] * 100;
+       total *= 100;
+
+       ttable_add_row(tt, "%s|%.2f%%|%.2f%%|%.2f%%|%.2f%%|%.2f%%", protection,
+                      critical, high, medium, low, total);
+}
+
+static void isis_print_frr_summary(struct vty *vty,
+                                  struct isis_spftree *spftree)
+{
+       struct ttable *tt;
+       char *table;
+       const char *tree_id_text = NULL;
+       uint32_t protectd[SPF_PREFIX_PRIO_MAX] = {0};
+       uint32_t unprotected[SPF_PREFIX_PRIO_MAX] = {0};
+       double coverage[SPF_PREFIX_PRIO_MAX] = {0};
+       uint32_t protected_total = 0, grand_total = 0;
+       double coverage_total;
+
+       if (!spftree)
+               return;
+
+       switch (spftree->tree_id) {
+       case SPFTREE_IPV4:
+               tree_id_text = "IPv4";
+               break;
+       case SPFTREE_IPV6:
+               tree_id_text = "IPv6";
+               break;
+       case SPFTREE_DSTSRC:
+               tree_id_text = "IPv6 (dst-src routing)";
+               break;
+       case SPFTREE_COUNT:
+               assert(!"isis_print_frr_summary shouldn't be called with SPFTREE_COUNT as type");
+               return;
+       }
+
+       vty_out(vty, " IS-IS %s %s Fast ReRoute summary:\n\n",
+               circuit_t2string(spftree->level), tree_id_text);
+
+       /* Prepare table. */
+       tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+       ttable_add_row(
+               tt,
+               "Protection \\ Priority|Critical|High    |Medium  |Low     |Total");
+       tt->style.cell.rpad = 2;
+       tt->style.corner = '+';
+       ttable_restyle(tt);
+       ttable_rowseps(tt, 0, BOTTOM, true, '-');
+
+       /* Compute unprotected and coverage totals. */
+       for (int priority = SPF_PREFIX_PRIO_CRITICAL;
+            priority < SPF_PREFIX_PRIO_MAX; priority++) {
+               uint32_t *lfa = spftree->lfa.protection_counters.lfa;
+               uint32_t *rlfa = spftree->lfa.protection_counters.rlfa;
+               uint32_t *tilfa = spftree->lfa.protection_counters.tilfa;
+               uint32_t *ecmp = spftree->lfa.protection_counters.ecmp;
+               uint32_t *total = spftree->lfa.protection_counters.total;
+
+               protectd[priority] = lfa[priority] + rlfa[priority]
+                                    + tilfa[priority] + ecmp[priority];
+               /* Safeguard to protect against possible inconsistencies. */
+               if (protectd[priority] > total[priority])
+                       protectd[priority] = total[priority];
+               unprotected[priority] = total[priority] - protectd[priority];
+               protected_total += protectd[priority];
+               grand_total += total[priority];
+
+               if (!total[priority])
+                       coverage[priority] = 0;
+               else
+                       coverage[priority] =
+                               protectd[priority] / (double)total[priority];
+       }
+
+       if (!grand_total)
+               coverage_total = 0;
+       else
+               coverage_total = protected_total / (double)grand_total;
+
+       /* Add rows. */
+       isis_print_frr_summary_line(tt, "Classic LFA",
+                                   spftree->lfa.protection_counters.lfa);
+       isis_print_frr_summary_line(tt, "Remote LFA",
+                                   spftree->lfa.protection_counters.rlfa);
+       isis_print_frr_summary_line(tt, "Topology Independent LFA",
+                                   spftree->lfa.protection_counters.tilfa);
+       isis_print_frr_summary_line(tt, "ECMP",
+                                   spftree->lfa.protection_counters.ecmp);
+       isis_print_frr_summary_line(tt, "Unprotected", unprotected);
+       isis_print_frr_summary_line_coverage(tt, "Protection coverage",
+                                            coverage, coverage_total);
+
+       /* Dump the generated table. */
+       table = ttable_dump(tt, "\n");
+       vty_out(vty, "%s\n", table);
+       XFREE(MTYPE_TMP, table);
+       ttable_del(tt);
+}
+
+static void show_isis_frr_summary_common(struct vty *vty, int levels,
+                                        struct isis *isis)
+{
+       struct listnode *node;
+       struct isis_area *area;
+
+       if (!isis->area_list || isis->area_list->count == 0)
+               return;
+
+       for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+               vty_out(vty, "Area %s:\n",
+                       area->area_tag ? area->area_tag : "null");
+
+               for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
+                       if ((level & levels) == 0)
+                               continue;
+
+                       if (area->ip_circuits > 0) {
+                               isis_print_frr_summary(
+                                       vty,
+                                       area->spftree[SPFTREE_IPV4][level - 1]);
+                       }
+                       if (area->ipv6_circuits > 0) {
+                               isis_print_frr_summary(
+                                       vty,
+                                       area->spftree[SPFTREE_IPV6][level - 1]);
+                       }
+                       if (isis_area_ipv6_dstsrc_enabled(area)) {
+                               isis_print_frr_summary(
+                                       vty, area->spftree[SPFTREE_DSTSRC]
+                                                         [level - 1]);
+                       }
+               }
+       }
+}
+
+DEFUN(show_isis_frr_summary, show_isis_frr_summary_cmd,
+      "show " PROTO_NAME
+      " [vrf <NAME|all>] fast-reroute summary"
+#ifndef FABRICD
+      " [<level-1|level-2>]"
+#endif
+      ,
+      SHOW_STR PROTO_HELP VRF_FULL_CMD_HELP_STR
+      "IS-IS FRR information\n"
+      "FRR summary\n"
+#ifndef FABRICD
+      "level-1 routes\n"
+      "level-2 routes\n"
+#endif
+)
+{
+       int levels;
+       struct isis *isis;
+       struct listnode *node;
+       const char *vrf_name = VRF_DEFAULT_NAME;
+       bool all_vrf = false;
+       int idx = 0;
+
+       if (argv_find(argv, argc, "level-1", &idx))
+               levels = ISIS_LEVEL1;
+       else if (argv_find(argv, argc, "level-2", &idx))
+               levels = ISIS_LEVEL2;
+       else
+               levels = ISIS_LEVEL1 | ISIS_LEVEL2;
+
+       if (!im) {
+               vty_out(vty, "IS-IS Routing Process not enabled\n");
+               return CMD_SUCCESS;
+       }
+       ISIS_FIND_VRF_ARGS(argv, argc, idx, vrf_name, all_vrf);
+
+       if (vrf_name) {
+               if (all_vrf) {
+                       for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
+                               show_isis_frr_summary_common(vty, levels, isis);
+                       return CMD_SUCCESS;
+               }
+               isis = isis_lookup_by_vrfname(vrf_name);
+               if (isis != NULL)
+                       show_isis_frr_summary_common(vty, levels, isis);
+       }
+
+       return CMD_SUCCESS;
+}
+
 void isis_spf_init(void)
 {
        install_element(VIEW_NODE, &show_isis_topology_cmd);
        install_element(VIEW_NODE, &show_isis_route_cmd);
+       install_element(VIEW_NODE, &show_isis_frr_summary_cmd);
 
        /* Register hook(s). */
        hook_register(isis_adj_state_change_hook, spf_adj_state_change);
index ad15d3e3c7fa4afcc5b78bc77caa67db3074cbb6..5b3aa593799bf347d609dd471bf96d82fc681f73 100644 (file)
@@ -31,6 +31,7 @@ struct isis_spftree;
 enum spf_type {
        SPF_TYPE_FORWARD = 1,
        SPF_TYPE_REVERSE,
+       SPF_TYPE_RLFA,
        SPF_TYPE_TI_LFA,
 };
 
@@ -39,13 +40,14 @@ struct isis_spf_adj {
        struct isis_adjacency *adj;
        uint32_t metric;
        struct isis_ext_subtlvs *subtlvs;
+       struct isis_lsp *lsp;
        struct {
                uint8_t desig_is_id[ISIS_SYS_ID_LEN + 1];
-               struct isis_lsp *lsp_pseudo;
        } lan;
        uint8_t flags;
 #define F_ISIS_SPF_ADJ_BROADCAST 0x01
 #define F_ISIS_SPF_ADJ_OLDMETRIC 0x02
+#define F_ISIS_SPF_ADJ_METRIC_INFINITY 0x04
 };
 
 struct isis_spftree *isis_spftree_new(struct isis_area *area,
index 9cb1a39b827253152eb2a49eacd1c070df87788d..79dfa3e164be09412598d9bb86a1423d096f7267 100644 (file)
@@ -54,6 +54,7 @@ struct isis_vertex_adj {
        struct isis_spf_adj *sadj;
        struct isis_sr_psid_info sr;
        struct mpls_label_stack *label_stack;
+       uint32_t lfa_metric;
 };
 
 /*
@@ -66,6 +67,7 @@ struct isis_vertex {
                struct {
                        struct prefix_pair p;
                        struct isis_sr_psid_info sr;
+                       enum spf_prefix_priority priority;
                } ip;
        } N;
        uint32_t d_N;     /* d(N) Distance from this IS      */
@@ -74,7 +76,9 @@ struct isis_vertex {
        struct list *parents;  /* list of parents for ECMP */
        struct hash *firsthops; /* first two hops to neighbor */
        uint64_t insert_counter;
+       uint8_t flags;
 };
+#define F_ISIS_VERTEX_LFA_PROTECTED    0x01
 
 /* Vertex Queue and associated functions */
 
@@ -193,6 +197,11 @@ static void isis_vertex_del(struct isis_vertex *vertex)
 bool isis_vertex_adj_exists(const struct isis_spftree *spftree,
                            const struct isis_vertex *vertex,
                            const struct isis_spf_adj *sadj);
+void isis_vertex_adj_free(void *arg);
+struct isis_vertex_adj *
+isis_vertex_adj_add(struct isis_spftree *spftree, struct isis_vertex *vertex,
+                   struct list *vadj_list, struct isis_spf_adj *sadj,
+                   struct isis_prefix_sid *psid, bool last_hop);
 
 __attribute__((__unused__))
 static void isis_vertex_queue_clear(struct isis_vertex_queue *queue)
@@ -341,6 +350,30 @@ struct isis_spftree {
                /* P-space and Q-space. */
                struct isis_spf_nodes p_space;
                struct isis_spf_nodes q_space;
+
+               /* Remote LFA related information. */
+               struct {
+                       /* List of RLFAs eligible to be installed. */
+                       struct rlfa_tree_head rlfas;
+
+                       /*
+                        * RLFA post-convergence SPTs (needed to activate RLFAs
+                        * once label information is received from LDP).
+                        */
+                       struct list *pc_spftrees;
+
+                       /* RLFA maximum metric (or zero if absent). */
+                       uint32_t max_metric;
+               } remote;
+
+               /* Protection counters. */
+               struct {
+                       uint32_t lfa[SPF_PREFIX_PRIO_MAX];
+                       uint32_t rlfa[SPF_PREFIX_PRIO_MAX];
+                       uint32_t tilfa[SPF_PREFIX_PRIO_MAX];
+                       uint32_t ecmp[SPF_PREFIX_PRIO_MAX];
+                       uint32_t total[SPF_PREFIX_PRIO_MAX];
+               } protection_counters;
        } lfa;
        uint8_t flags;
 };
index af419961d56fb7974306de28ec3b6a23a20e7471..a97c19a8bc54fa4e19b37ff9eb7f931a69e0df65 100644 (file)
@@ -4850,7 +4850,7 @@ void isis_tlvs_add_spine_leaf(struct isis_tlvs *tlvs, uint8_t tier,
 struct isis_mt_router_info *
 isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid)
 {
-       if (tlvs->mt_router_info_empty)
+       if (!tlvs || tlvs->mt_router_info_empty)
                return NULL;
 
        struct isis_mt_router_info *rv;
index 54ded8121d740a9c0b6b498bb421c8791d7a1f50..037f91f0b87340e6cffc0d45432b886d887634ae 100644 (file)
@@ -42,6 +42,9 @@ struct isis_area_address {
        uint8_t len;
 };
 
+#define ISIS_WIDE_METRIC_INFINITY   0xFFFFFE
+#define ISIS_NARROW_METRIC_INFINITY 62
+
 struct isis_oldstyle_reach;
 struct isis_oldstyle_reach {
        struct isis_oldstyle_reach *next;
index 8bc56339977bb795495735d4baa903c96fa37520..703532234ab55a0ffc1a7da93347e1a484b144d9 100644 (file)
@@ -47,6 +47,8 @@
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_csm.h"
 #include "isisd/isis_lsp.h"
+#include "isisd/isis_spf.h"
+#include "isisd/isis_spf_private.h"
 #include "isisd/isis_route.h"
 #include "isisd/isis_zebra.h"
 #include "isisd/isis_adjacency.h"
@@ -207,35 +209,30 @@ static int isis_zebra_add_nexthops(struct isis *isis, struct list *nexthops,
                api_nh->ifindex = nexthop->ifindex;
 
                /* Add MPLS label(s). */
-               switch (type) {
-               case ISIS_NEXTHOP_MAIN:
-                       if (nexthop->sr.present) {
-                               api_nh->label_num = 1;
-                               api_nh->labels[0] = nexthop->sr.label;
-                       } else if (mpls_lsp)
+               if (nexthop->label_stack) {
+                       api_nh->label_num = nexthop->label_stack->num_labels;
+                       memcpy(api_nh->labels, nexthop->label_stack->label,
+                              sizeof(mpls_label_t) * api_nh->label_num);
+               } else if (nexthop->sr.present) {
+                       api_nh->label_num = 1;
+                       api_nh->labels[0] = nexthop->sr.label;
+               } else if (mpls_lsp) {
+                       switch (type) {
+                       case ISIS_NEXTHOP_MAIN:
                                /*
                                 * Do not use non-SR enabled nexthops to prevent
                                 * broken LSPs from being formed.
                                 */
                                continue;
-                       break;
-               case ISIS_NEXTHOP_BACKUP:
-                       if (nexthop->label_stack) {
-                               api_nh->label_num =
-                                       nexthop->label_stack->num_labels;
-                               memcpy(api_nh->labels,
-                                      nexthop->label_stack->label,
-                                      sizeof(mpls_label_t)
-                                              * api_nh->label_num);
-                       } else if (mpls_lsp) {
+                       case ISIS_NEXTHOP_BACKUP:
                                /*
                                 * This is necessary because zebra requires
                                 * the nexthops of MPLS LSPs to be labeled.
                                 */
                                api_nh->label_num = 1;
                                api_nh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
+                               break;
                        }
-                       break;
                }
 
                /* Backup nexthop handling. */
@@ -263,8 +260,14 @@ void isis_zebra_route_add_route(struct isis *isis, struct prefix *prefix,
        struct zapi_route api;
        int count = 0;
 
-       if (zclient->sock < 0 || list_isempty(route_info->nexthops))
+       if (zclient->sock < 0)
+               return;
+
+       /* Uninstall the route if it doesn't have any valid nexthop. */
+       if (list_isempty(route_info->nexthops)) {
+               isis_zebra_route_del_route(isis, prefix, src_p, route_info);
                return;
+       }
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = isis->vrf_id;
@@ -539,6 +542,72 @@ void isis_zebra_redistribute_unset(afi_t afi, int type)
                                     type, 0, VRF_DEFAULT);
 }
 
+/**
+ * Register RLFA with LDP.
+ */
+int isis_zebra_rlfa_register(struct isis_spftree *spftree, struct rlfa *rlfa)
+{
+       struct isis_area *area = spftree->area;
+       struct zapi_rlfa_request zr = {};
+       int ret;
+
+       if (!zclient)
+               return 0;
+
+       zr.igp.vrf_id = area->isis->vrf_id;
+       zr.igp.protocol = ZEBRA_ROUTE_ISIS;
+       strlcpy(zr.igp.isis.area_tag, area->area_tag,
+               sizeof(zr.igp.isis.area_tag));
+       zr.igp.isis.spf.tree_id = spftree->tree_id;
+       zr.igp.isis.spf.level = spftree->level;
+       zr.igp.isis.spf.run_id = spftree->runcount;
+       zr.destination = rlfa->prefix;
+       zr.pq_address = rlfa->pq_address;
+
+       zlog_debug("ISIS-LFA: registering RLFA %pFX@%pI4 with LDP",
+                  &rlfa->prefix, &rlfa->pq_address);
+
+       ret = zclient_send_opaque_unicast(zclient, LDP_RLFA_REGISTER,
+                                         ZEBRA_ROUTE_LDP, 0, 0,
+                                         (const uint8_t *)&zr, sizeof(zr));
+       if (ret == ZCLIENT_SEND_FAILURE) {
+               zlog_warn("ISIS-LFA: failed to register RLFA with LDP");
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * Unregister all RLFAs from the given SPF tree with LDP.
+ */
+void isis_zebra_rlfa_unregister_all(struct isis_spftree *spftree)
+{
+       struct isis_area *area = spftree->area;
+       struct zapi_rlfa_igp igp = {};
+       int ret;
+
+       if (!zclient || spftree->type != SPF_TYPE_FORWARD
+           || CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
+               return;
+
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: unregistering all RLFAs with LDP");
+
+       igp.vrf_id = area->isis->vrf_id;
+       igp.protocol = ZEBRA_ROUTE_ISIS;
+       strlcpy(igp.isis.area_tag, area->area_tag, sizeof(igp.isis.area_tag));
+       igp.isis.spf.tree_id = spftree->tree_id;
+       igp.isis.spf.level = spftree->level;
+       igp.isis.spf.run_id = spftree->runcount;
+
+       ret = zclient_send_opaque_unicast(zclient, LDP_RLFA_UNREGISTER_ALL,
+                                         ZEBRA_ROUTE_LDP, 0, 0,
+                                         (const uint8_t *)&igp, sizeof(igp));
+       if (ret == ZCLIENT_SEND_FAILURE)
+               zlog_warn("ISIS-LFA: failed to unregister RLFA with LDP");
+}
+
 /* Label Manager Functions */
 
 /**
@@ -618,7 +687,7 @@ int isis_zebra_label_manager_connect(void)
        set_nonblocking(zclient_sync->sock);
 
        /* Send hello to notify zebra this is a synchronous client */
-       if (zclient_send_hello(zclient_sync) < 0) {
+       if (zclient_send_hello(zclient_sync) == ZCLIENT_SEND_FAILURE) {
                zlog_warn("%s: failed sending hello for synchronous zclient!",
                          __func__);
                close(zclient_sync->sock);
@@ -658,6 +727,7 @@ void isis_zebra_vrf_register(struct isis *isis)
 static void isis_zebra_connected(struct zclient *zclient)
 {
        zclient_send_reg_requests(zclient, VRF_DEFAULT);
+       zclient_register_opaque(zclient, LDP_RLFA_LABELS);
 }
 
 /*
@@ -669,7 +739,7 @@ static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
        struct zapi_opaque_msg info;
        struct ldp_igp_sync_if_state state;
        struct ldp_igp_sync_announce announce;
-       struct ldp_igp_sync_hello hello;
+       struct zapi_rlfa_response rlfa;
        int ret = 0;
 
        s = zclient->ibuf;
@@ -685,9 +755,9 @@ static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
                STREAM_GET(&announce, s, sizeof(announce));
                ret = isis_ldp_sync_announce_update(announce);
                break;
-       case LDP_IGP_SYNC_HELLO_UPDATE:
-               STREAM_GET(&hello, s, sizeof(hello));
-               ret = isis_ldp_sync_hello_update(hello);
+       case LDP_RLFA_LABELS:
+               STREAM_GET(&rlfa, s, sizeof(rlfa));
+               isis_rlfa_process_ldp_response(&rlfa);
                break;
        default:
                break;
@@ -698,6 +768,21 @@ stream_failure:
        return ret;
 }
 
+static int isis_zebra_client_close_notify(ZAPI_CALLBACK_ARGS)
+{
+       int ret = 0;
+
+       struct zapi_client_close_info info;
+
+       if (zapi_client_close_notify_decode(zclient->ibuf, &info) < 0)
+               return -1;
+
+       isis_ldp_sync_handle_client_close(&info);
+       isis_ldp_rlfa_handle_client_close(&info);
+
+       return ret;
+}
+
 void isis_zebra_init(struct thread_master *master, int instance)
 {
        /* Initialize asynchronous zclient. */
@@ -726,10 +811,13 @@ void isis_zebra_init(struct thread_master *master, int instance)
        zclient_sync->privs = &isisd_privs;
 
        zclient->opaque_msg_handler = isis_opaque_msg_handler;
+
+       zclient->zebra_client_close_notify = isis_zebra_client_close_notify;
 }
 
 void isis_zebra_stop(void)
 {
+       zclient_unregister_opaque(zclient, LDP_RLFA_LABELS);
        zclient_stop(zclient_sync);
        zclient_free(zclient_sync);
        zclient_stop(zclient);
index c5c52a6bc6bd262deca9944cd3108d0e86bef968..b44ec4f085484708d00ff670c29ee507237efd9a 100644 (file)
@@ -59,6 +59,8 @@ void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra);
 int isis_distribute_list_update(int routetype);
 void isis_zebra_redistribute_set(afi_t afi, int type);
 void isis_zebra_redistribute_unset(afi_t afi, int type);
+int isis_zebra_rlfa_register(struct isis_spftree *spftree, struct rlfa *rlfa);
+void isis_zebra_rlfa_unregister_all(struct isis_spftree *spftree);
 bool isis_zebra_label_manager_ready(void);
 int isis_zebra_label_manager_connect(void);
 int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size);
index 950cdc281f1bab5ed154c0a93c2cb0636d8b12c5..eabebab4e000c3bc2b4bf5611ce88a6b987bc0b8 100644 (file)
@@ -31,6 +31,8 @@
 #include "linklist.h"
 #include "if.h"
 #include "hash.h"
+#include "filter.h"
+#include "plist.h"
 #include "stream.h"
 #include "prefix.h"
 #include "table.h"
@@ -77,7 +79,7 @@ unsigned long debug_bfd;
 unsigned long debug_tx_queue;
 unsigned long debug_sr;
 unsigned long debug_ldp_sync;
-unsigned long debug_tilfa;
+unsigned long debug_lfa;
 
 DEFINE_QOBJ_TYPE(isis_area)
 
@@ -310,6 +312,10 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
        area->lsp_frag_threshold = 90; /* not currently configurable */
        area->lsp_mtu =
                yang_get_default_uint16("/frr-isisd:isis/instance/lsp/mtu");
+       area->lfa_load_sharing[0] = yang_get_default_bool(
+               "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/load-sharing");
+       area->lfa_load_sharing[1] = yang_get_default_bool(
+               "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/load-sharing");
 #else
        area->max_lsp_lifetime[0] = DEFAULT_LSP_LIFETIME;    /* 1200 */
        area->max_lsp_lifetime[1] = DEFAULT_LSP_LIFETIME;    /* 1200 */
@@ -324,7 +330,13 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
        area->newmetric = 1;
        area->lsp_frag_threshold = 90;
        area->lsp_mtu = DEFAULT_LSP_MTU;
+       area->lfa_load_sharing[0] = true;
+       area->lfa_load_sharing[1] = true;
 #endif /* ifndef FABRICD */
+       area->lfa_priority_limit[0] = SPF_PREFIX_PRIO_LOW;
+       area->lfa_priority_limit[1] = SPF_PREFIX_PRIO_LOW;
+       isis_lfa_tiebreakers_init(area, ISIS_LEVEL1);
+       isis_lfa_tiebreakers_init(area, ISIS_LEVEL2);
 
        area_mt_init(area);
 
@@ -461,9 +473,20 @@ void isis_area_destroy(struct isis_area *area)
        }
        area->area_addrs = NULL;
 
+       for (int i = SPF_PREFIX_PRIO_CRITICAL; i <= SPF_PREFIX_PRIO_MEDIUM;
+            i++) {
+               struct spf_prefix_priority_acl *ppa;
+
+               ppa = &area->spf_prefix_priorities[i];
+               XFREE(MTYPE_ISIS_ACL_NAME, ppa->name);
+       }
+       isis_lfa_tiebreakers_clear(area, ISIS_LEVEL1);
+       isis_lfa_tiebreakers_clear(area, ISIS_LEVEL2);
+
        thread_cancel(&area->t_tick);
        thread_cancel(&area->t_lsp_refresh[0]);
        thread_cancel(&area->t_lsp_refresh[1]);
+       thread_cancel(&area->t_rlfa_rib_update);
 
        thread_cancel_event(master, area);
 
@@ -605,6 +628,57 @@ void isis_terminate()
                isis_finish(isis);
 }
 
+void isis_filter_update(struct access_list *access)
+{
+       struct isis *isis;
+       struct isis_area *area;
+       struct listnode *node, *anode;
+
+       for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
+               for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
+                       for (int i = SPF_PREFIX_PRIO_CRITICAL;
+                            i <= SPF_PREFIX_PRIO_MEDIUM; i++) {
+                               struct spf_prefix_priority_acl *ppa;
+
+                               ppa = &area->spf_prefix_priorities[i];
+                               ppa->list_v4 =
+                                       access_list_lookup(AFI_IP, ppa->name);
+                               ppa->list_v6 =
+                                       access_list_lookup(AFI_IP6, ppa->name);
+                       }
+                       lsp_regenerate_schedule(area, area->is_type, 0);
+               }
+       }
+}
+
+void isis_prefix_list_update(struct prefix_list *plist)
+{
+       struct isis *isis;
+       struct isis_area *area;
+       struct listnode *node, *anode;
+
+       for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
+               for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
+                       for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
+                            level++) {
+                               const char *plist_name =
+                                       prefix_list_name(plist);
+
+                               if (!area->rlfa_plist_name[level - 1])
+                                       continue;
+
+                               if (!strmatch(area->rlfa_plist_name[level - 1],
+                                             plist_name))
+                                       continue;
+
+                               area->rlfa_plist[level - 1] =
+                                       prefix_list_lookup(AFI_IP, plist_name);
+                               lsp_regenerate_schedule(area, area->is_type, 0);
+                       }
+               }
+       }
+}
+
 #ifdef FABRICD
 static void area_set_mt_enabled(struct isis_area *area, uint16_t mtid,
                                bool enabled)
@@ -1199,8 +1273,8 @@ void print_debug(struct vty *vty, int flags, int onoff)
        if (flags & DEBUG_SR)
                vty_out(vty, "IS-IS Segment Routing events debugging is %s\n",
                        onoffs);
-       if (flags & DEBUG_TILFA)
-               vty_out(vty, "IS-IS TI-LFA events debugging is %s\n", onoffs);
+       if (flags & DEBUG_LFA)
+               vty_out(vty, "IS-IS LFA events debugging is %s\n", onoffs);
        if (flags & DEBUG_UPDATE_PACKETS)
                vty_out(vty, "IS-IS Update related packet debugging is %s\n",
                        onoffs);
@@ -1295,8 +1369,8 @@ static int config_write_debug(struct vty *vty)
                vty_out(vty, "debug " PROTO_NAME " sr-events\n");
                write++;
        }
-       if (IS_DEBUG_TILFA) {
-               vty_out(vty, "debug " PROTO_NAME " ti-lfa\n");
+       if (IS_DEBUG_LFA) {
+               vty_out(vty, "debug " PROTO_NAME " lfa\n");
                write++;
        }
        if (IS_DEBUG_UPDATE_PACKETS) {
@@ -1529,29 +1603,29 @@ DEFUN (no_debug_isis_srevents,
        return CMD_SUCCESS;
 }
 
-DEFUN (debug_isis_tilfa,
-       debug_isis_tilfa_cmd,
-       "debug " PROTO_NAME " ti-lfa",
+DEFUN (debug_isis_lfa,
+       debug_isis_lfa_cmd,
+       "debug " PROTO_NAME " lfa",
        DEBUG_STR
        PROTO_HELP
-       "IS-IS TI-LFA Events\n")
+       "IS-IS LFA Events\n")
 {
-       debug_tilfa |= DEBUG_TILFA;
-       print_debug(vty, DEBUG_TILFA, 1);
+       debug_lfa |= DEBUG_LFA;
+       print_debug(vty, DEBUG_LFA, 1);
 
        return CMD_SUCCESS;
 }
 
-DEFUN (no_debug_isis_tilfa,
-       no_debug_isis_tilfa_cmd,
-       "no debug " PROTO_NAME " ti-lfa",
+DEFUN (no_debug_isis_lfa,
+       no_debug_isis_lfa_cmd,
+       "no debug " PROTO_NAME " lfa",
        NO_STR
        UNDEBUG_STR
        PROTO_HELP
-       "IS-IS TI-LFA Events\n")
+       "IS-IS LFA Events\n")
 {
-       debug_tilfa &= ~DEBUG_TILFA;
-       print_debug(vty, DEBUG_TILFA, 0);
+       debug_lfa &= ~DEBUG_LFA;
+       print_debug(vty, DEBUG_LFA, 0);
 
        return CMD_SUCCESS;
 }
@@ -2892,8 +2966,8 @@ void isis_init(void)
        install_element(ENABLE_NODE, &no_debug_isis_spfevents_cmd);
        install_element(ENABLE_NODE, &debug_isis_srevents_cmd);
        install_element(ENABLE_NODE, &no_debug_isis_srevents_cmd);
-       install_element(ENABLE_NODE, &debug_isis_tilfa_cmd);
-       install_element(ENABLE_NODE, &no_debug_isis_tilfa_cmd);
+       install_element(ENABLE_NODE, &debug_isis_lfa_cmd);
+       install_element(ENABLE_NODE, &no_debug_isis_lfa_cmd);
        install_element(ENABLE_NODE, &debug_isis_rtevents_cmd);
        install_element(ENABLE_NODE, &no_debug_isis_rtevents_cmd);
        install_element(ENABLE_NODE, &debug_isis_events_cmd);
@@ -2923,8 +2997,8 @@ void isis_init(void)
        install_element(CONFIG_NODE, &no_debug_isis_spfevents_cmd);
        install_element(CONFIG_NODE, &debug_isis_srevents_cmd);
        install_element(CONFIG_NODE, &no_debug_isis_srevents_cmd);
-       install_element(CONFIG_NODE, &debug_isis_tilfa_cmd);
-       install_element(CONFIG_NODE, &no_debug_isis_tilfa_cmd);
+       install_element(CONFIG_NODE, &debug_isis_lfa_cmd);
+       install_element(CONFIG_NODE, &no_debug_isis_lfa_cmd);
        install_element(CONFIG_NODE, &debug_isis_rtevents_cmd);
        install_element(CONFIG_NODE, &no_debug_isis_rtevents_cmd);
        install_element(CONFIG_NODE, &debug_isis_events_cmd);
index 921df4d7ef14aca48d054019013f45705e6bc225..9b903eed48098be08b8d638fbfa855fee46420c6 100644 (file)
@@ -33,6 +33,7 @@
 #include "isisd/isis_sr.h"
 #include "isis_flags.h"
 #include "isis_lsp.h"
+#include "isis_lfa.h"
 #include "isis_memory.h"
 #include "qobj.h"
 #include "ldp_sync.h"
@@ -130,6 +131,7 @@ struct isis_area {
        struct thread *t_tick; /* LSP walker */
        struct thread *t_lsp_refresh[ISIS_LEVELS];
        struct timeval last_lsp_refresh_event[ISIS_LEVELS];
+       struct thread *t_rlfa_rib_update;
        /* t_lsp_refresh is used in two ways:
         * a) regular refresh of LSPs
         * b) (possibly throttled) updates to LSPs
@@ -188,8 +190,18 @@ struct isis_area {
        struct isis_sr_db srdb;
        int ipv6_circuits;
        bool purge_originator;
+       /* SPF prefix priorities. */
+       struct spf_prefix_priority_acl
+               spf_prefix_priorities[SPF_PREFIX_PRIO_MAX];
        /* Fast Re-Route information. */
        size_t lfa_protected_links[ISIS_LEVELS];
+       size_t lfa_load_sharing[ISIS_LEVELS];
+       enum spf_prefix_priority lfa_priority_limit[ISIS_LEVELS];
+       struct lfa_tiebreaker_tree_head lfa_tiebreakers[ISIS_LEVELS];
+       char *rlfa_plist_name[ISIS_LEVELS];
+       struct prefix_list *rlfa_plist[ISIS_LEVELS];
+       size_t rlfa_protected_links[ISIS_LEVELS];
+       size_t tilfa_protected_links[ISIS_LEVELS];
        /* Counters */
        uint32_t circuit_state_changes;
        struct isis_redist redist_settings[REDIST_PROTOCOL_COUNT]
@@ -231,6 +243,8 @@ struct isis_area *isis_area_lookup_by_vrf(const char *area_tag,
                                          const char *vrf_name);
 int isis_area_get(struct vty *vty, const char *area_tag);
 void isis_area_destroy(struct isis_area *area);
+void isis_filter_update(struct access_list *access);
+void isis_prefix_list_update(struct prefix_list *plist);
 void print_debug(struct vty *, int, int);
 struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv,
                             struct isis *isis);
@@ -280,7 +294,7 @@ extern unsigned long debug_bfd;
 extern unsigned long debug_tx_queue;
 extern unsigned long debug_sr;
 extern unsigned long debug_ldp_sync;
-extern unsigned long debug_tilfa;
+extern unsigned long debug_lfa;
 
 #define DEBUG_ADJ_PACKETS                (1<<0)
 #define DEBUG_SNP_PACKETS                (1<<1)
@@ -296,7 +310,7 @@ extern unsigned long debug_tilfa;
 #define DEBUG_TX_QUEUE                   (1<<11)
 #define DEBUG_SR                         (1<<12)
 #define DEBUG_LDP_SYNC                   (1<<13)
-#define DEBUG_TILFA                      (1<<14)
+#define DEBUG_LFA                        (1<<14)
 
 /* Debug related macro. */
 #define IS_DEBUG_ADJ_PACKETS (debug_adj_pkt & DEBUG_ADJ_PACKETS)
@@ -313,7 +327,7 @@ extern unsigned long debug_tilfa;
 #define IS_DEBUG_TX_QUEUE (debug_tx_queue & DEBUG_TX_QUEUE)
 #define IS_DEBUG_SR (debug_sr & DEBUG_SR)
 #define IS_DEBUG_LDP_SYNC (debug_ldp_sync & DEBUG_LDP_SYNC)
-#define IS_DEBUG_TILFA (debug_tilfa & DEBUG_TILFA)
+#define IS_DEBUG_LFA (debug_lfa & DEBUG_LFA)
 
 #define lsp_debug(...)                                                         \
        do {                                                                   \
index 795a41491cd4fe9ade5f0093f46695104e6d4538..d390e70ad0d0cd8b9d794e683557173d41633444 100644 (file)
@@ -183,7 +183,8 @@ adj_itimer(struct thread *thread)
 
        if (adj->source.type == HELLO_TARGETED) {
                if (!(adj->source.target->flags & F_TNBR_CONFIGURED) &&
-                   adj->source.target->pw_count == 0) {
+                   adj->source.target->pw_count == 0 &&
+                   adj->source.target->rlfa_count == 0) {
                        /* remove dynamic targeted neighbor */
                        tnbr_del(leconf, adj->source.target);
                        return (0);
@@ -259,7 +260,7 @@ struct tnbr *
 tnbr_check(struct ldpd_conf *xconf, struct tnbr *tnbr)
 {
        if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) &&
-           tnbr->pw_count == 0) {
+           tnbr->pw_count == 0 && tnbr->rlfa_count == 0) {
                tnbr_del(xconf, tnbr);
                return (NULL);
        }
index 327cb32434afb0578a7999babf341ba3ed7d92a9..5aa14ed067f9b0d1a0e8009e59651767f5265ade 100644 (file)
@@ -67,7 +67,8 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
                af = tnbr->af;
                holdtime = tnbr_get_hello_holdtime(tnbr);
                flags = F_HELLO_TARGETED;
-               if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count)
+               if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count
+                   || tnbr->rlfa_count)
                        flags |= F_HELLO_REQ_TARG;
                fd = (ldp_af_global_get(&global, af))->ldp_edisc_socket;
 
index 67b695150e4fe72769f8dff09865ec02b1cd5093..69338b8bad6a407d93ce19b428c0bdc1dc3de010 100644 (file)
@@ -27,6 +27,7 @@
 #include "log.h"
 #include "lde.h"
 #include "ldp_debug.h"
+#include "rlfa.h"
 
 #include <lib/log.h>
 #include "memory.h"
@@ -73,6 +74,7 @@ struct ldpd_conf      *ldeconf;
 struct nbr_tree                 lde_nbrs = RB_INITIALIZER(&lde_nbrs);
 
 static struct imsgev   *iev_ldpe;
+static struct imsgev    iev_main_sync_data;
 static struct imsgev   *iev_main, *iev_main_sync;
 
 /* lde privileges */
@@ -148,8 +150,8 @@ lde(void)
                        &iev_main->ev_read);
        iev_main->handler_write = ldp_write_handler;
 
-       if ((iev_main_sync = calloc(1, sizeof(struct imsgev))) == NULL)
-               fatal(NULL);
+       memset(&iev_main_sync_data, 0, sizeof(iev_main_sync_data));
+       iev_main_sync = &iev_main_sync_data;
        imsg_init(&iev_main_sync->ibuf, LDPD_FD_SYNC);
 
        /* create base configuration */
@@ -203,7 +205,6 @@ lde_shutdown(void)
        if (iev_ldpe)
                free(iev_ldpe);
        free(iev_main);
-       free(iev_main_sync);
 
        log_info("label decision engine exiting");
 
@@ -444,6 +445,10 @@ lde_dispatch_parent(struct thread *thread)
        int                      shut = 0;
        struct fec               fec;
        struct ldp_access       *laccess;
+       struct ldp_rlfa_node     *rnode, *rntmp;
+       struct ldp_rlfa_client   *rclient;
+       struct zapi_rlfa_request *rlfa_req;
+       struct zapi_rlfa_igp     *rlfa_igp;
 
        iev->ev_read = NULL;
 
@@ -650,6 +655,42 @@ lde_dispatch_parent(struct thread *thread)
                        lde_check_filter_af(AF_INET6, &ldeconf->ipv6,
                                laccess->name);
                        break;
+               case IMSG_RLFA_REG:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct zapi_rlfa_request)) {
+                               log_warnx("%s: wrong imsg len", __func__);
+                               break;
+                       }
+                       rlfa_req = imsg.data;
+                       rnode = rlfa_node_find(&rlfa_req->destination,
+                                              rlfa_req->pq_address);
+                       if (!rnode)
+                               rnode = rlfa_node_new(&rlfa_req->destination,
+                                                     rlfa_req->pq_address);
+                       rclient = rlfa_client_find(rnode, &rlfa_req->igp);
+                       if (rclient)
+                               /* RLFA already registered - do nothing */
+                               break;
+                       rclient = rlfa_client_new(rnode, &rlfa_req->igp);
+                       lde_rlfa_check(rclient);
+                       break;
+               case IMSG_RLFA_UNREG_ALL:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct zapi_rlfa_igp)) {
+                               log_warnx("%s: wrong imsg len", __func__);
+                               break;
+                       }
+                       rlfa_igp = imsg.data;
+
+                       RB_FOREACH_SAFE (rnode, ldp_rlfa_node_head,
+                                        &rlfa_node_tree, rntmp) {
+                               rclient = rlfa_client_find(rnode, rlfa_igp);
+                               if (!rclient)
+                                       continue;
+
+                               rlfa_client_del(rclient);
+                       }
+                       break;
                default:
                        log_debug("%s: unexpected imsg %d", __func__,
                            imsg.hdr.type);
@@ -875,6 +916,48 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
        }
 }
 
+void
+lde_fec2prefix(const struct fec *fec, struct prefix *prefix)
+{
+       memset(prefix, 0, sizeof(*prefix));
+       switch (fec->type) {
+       case FEC_TYPE_IPV4:
+               prefix->family = AF_INET;
+               prefix->u.prefix4 = fec->u.ipv4.prefix;
+               prefix->prefixlen = fec->u.ipv4.prefixlen;
+               break;
+       case FEC_TYPE_IPV6:
+               prefix->family = AF_INET6;
+               prefix->u.prefix6 = fec->u.ipv6.prefix;
+               prefix->prefixlen = fec->u.ipv6.prefixlen;
+               break;
+       default:
+               prefix->family = AF_UNSPEC;
+               break;
+       }
+}
+
+void
+lde_prefix2fec(const struct prefix *prefix, struct fec *fec)
+{
+       memset(fec, 0, sizeof(*fec));
+       switch (prefix->family) {
+       case AF_INET:
+               fec->type = FEC_TYPE_IPV4;
+               fec->u.ipv4.prefix = prefix->u.prefix4;
+               fec->u.ipv4.prefixlen = prefix->prefixlen;
+               break;
+       case AF_INET6:
+               fec->type = FEC_TYPE_IPV6;
+               fec->u.ipv6.prefix = prefix->u.prefix6;
+               fec->u.ipv6.prefixlen = prefix->prefixlen;
+               break;
+       default:
+               fatalx("lde_prefix2fec: unknown af");
+               break;
+       }
+}
+
 void
 lde_fec2map(struct fec *fec, struct map *map)
 {
@@ -1388,6 +1471,9 @@ lde_nbr_del(struct lde_nbr *ln)
        RB_FOREACH(f, fec_tree, &ft) {
                fn = (struct fec_node *)f;
 
+               /* Update RLFA clients. */
+               lde_rlfa_update_clients(f, ln, MPLS_INVALID_LABEL);
+
                LIST_FOREACH(fnh, &fn->nexthops, entry) {
                        switch (f->type) {
                        case FEC_TYPE_IPV4:
@@ -2092,7 +2178,7 @@ static void zclient_sync_init(void)
        sock_set_nonblock(zclient_sync->sock);
 
        /* Send hello to notify zebra this is a synchronous client */
-       if (zclient_send_hello(zclient_sync) < 0) {
+       if (zclient_send_hello(zclient_sync) == ZCLIENT_SEND_FAILURE) {
                log_warnx("Error sending hello for synchronous zclient!");
                goto retry;
        }
index 660aeafb34bf309f5a851252dd9252275c3144d2..e09be01ece58ac4ba9fe4d7b396a478a86b93f0d 100644 (file)
@@ -156,6 +156,8 @@ uint32_t     lde_update_label(struct fec_node *);
 void            lde_free_label(uint32_t label);
 void            lde_send_change_klabel(struct fec_node *, struct fec_nh *);
 void            lde_send_delete_klabel(struct fec_node *, struct fec_nh *);
+void            lde_fec2prefix(const struct fec *fec, struct prefix *prefix);
+void            lde_prefix2fec(const struct prefix *prefix, struct fec *fec);
 void            lde_fec2map(struct fec *, struct map *);
 void            lde_map2fec(struct map *, struct in_addr, struct fec *);
 void            lde_send_labelmapping(struct lde_nbr *, struct fec_node *,
index 9db931677dc38072639150dc7dc4919d436cfbe4..0f91f49920ad7d274130c4219e67441e9a525140 100644 (file)
@@ -23,6 +23,7 @@
 #include "ldpe.h"
 #include "lde.h"
 #include "log.h"
+#include "rlfa.h"
 
 #include "mpls.h"
 
@@ -601,6 +602,10 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln, int rcvd_label_mapping)
                        break;
                }
        }
+
+       /* Update RLFA clients. */
+       lde_rlfa_update_clients(&fec, ln, map->label);
+
        /* LMp.13 & LMp.16: Record the mapping from this peer */
        if (me == NULL)
                me = lde_map_add(ln, fn, 0);
@@ -858,6 +863,9 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
                fnh->remote_label = NO_LABEL;
        }
 
+       /* Update RLFA clients. */
+       lde_rlfa_update_clients(&fec, ln, MPLS_INVALID_LABEL);
+
        /* LWd.2: send label release */
        lde_send_labelrelease(ln, fn, NULL, map->label);
 
@@ -940,6 +948,9 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
                        fnh->remote_label = NO_LABEL;
                }
 
+               /* Update RLFA clients. */
+               lde_rlfa_update_clients(f, ln, MPLS_INVALID_LABEL);
+
                /* LWd.3: check previously received label mapping */
                if (me && (map->label == NO_LABEL ||
                    map->label == me->map.label))
index 3852d8d23b3072d52c0147908f584281d07599f5..ea86c2dc039c40fbc474718066d7689e6dc7b8c8 100644 (file)
@@ -51,8 +51,6 @@ static void   ldp_zebra_opaque_register(void);
 static void    ldp_zebra_opaque_unregister(void);
 static int     ldp_sync_zebra_send_announce(void);
 static int     ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS);
-static void    ldp_sync_zebra_start_hello_timer(void);
-static int     ldp_sync_zebra_hello(struct thread *thread);
 static void    ldp_sync_zebra_init(void);
 
 static struct zclient  *zclient;
@@ -116,19 +114,27 @@ static void
 ldp_zebra_opaque_register(void)
 {
        zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST);
+       zclient_register_opaque(zclient, LDP_RLFA_REGISTER);
+       zclient_register_opaque(zclient, LDP_RLFA_UNREGISTER_ALL);
 }
 
 static void
 ldp_zebra_opaque_unregister(void)
 {
        zclient_unregister_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST);
+       zclient_unregister_opaque(zclient, LDP_RLFA_REGISTER);
+       zclient_unregister_opaque(zclient, LDP_RLFA_UNREGISTER_ALL);
 }
 
 int
 ldp_sync_zebra_send_state_update(struct ldp_igp_sync_if_state *state)
 {
-        return zclient_send_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE,
-               (const uint8_t *) state, sizeof(*state));
+       if (zclient_send_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE,
+                               (const uint8_t *)state, sizeof(*state))
+           == ZCLIENT_SEND_FAILURE)
+               return -1;
+       else
+               return 0;
 }
 
 static int
@@ -137,8 +143,27 @@ ldp_sync_zebra_send_announce(void)
        struct ldp_igp_sync_announce announce;
        announce.proto = ZEBRA_ROUTE_LDP;
 
-        return zclient_send_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE,
-               (const uint8_t *) &announce, sizeof(announce));
+       if (zclient_send_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE,
+                               (const uint8_t *)&announce, sizeof(announce))
+           == ZCLIENT_SEND_FAILURE)
+               return -1;
+       else
+               return 0;
+}
+
+int ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response *rlfa_labels)
+{
+       int ret;
+
+       ret = zclient_send_opaque(zclient, LDP_RLFA_LABELS,
+                                 (const uint8_t *)rlfa_labels,
+                                 sizeof(*rlfa_labels));
+       if (ret == ZCLIENT_SEND_FAILURE) {
+               log_warn("failed to send RLFA labels to IGP");
+               return -1;
+       }
+
+       return 0;
 }
 
 static int
@@ -147,6 +172,8 @@ ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
        struct stream *s;
        struct zapi_opaque_msg info;
        struct ldp_igp_sync_if_state_req state_req;
+       struct zapi_rlfa_igp igp;
+       struct zapi_rlfa_request rlfa;
 
         s = zclient->ibuf;
 
@@ -159,6 +186,14 @@ ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
                main_imsg_compose_ldpe(IMSG_LDP_SYNC_IF_STATE_REQUEST, 0, &state_req,
                            sizeof(state_req));
                break;
+       case LDP_RLFA_REGISTER:
+               STREAM_GET(&rlfa, s, sizeof(rlfa));
+               main_imsg_compose_both(IMSG_RLFA_REG, &rlfa, sizeof(rlfa));
+               break;
+       case LDP_RLFA_UNREGISTER_ALL:
+               STREAM_GET(&igp, s, sizeof(igp));
+               main_imsg_compose_both(IMSG_RLFA_UNREG_ALL, &igp, sizeof(igp));
+               break;
        default:
                break;
        }
@@ -167,40 +202,12 @@ stream_failure:
         return 0;
 }
 
-static void
-ldp_sync_zebra_start_hello_timer(void)
-{
-       thread_add_timer_msec(master, ldp_sync_zebra_hello, NULL, 250, NULL);
-}
-
-static int
-ldp_sync_zebra_hello(struct thread *thread)
-{
-       static unsigned int sequence = 0;
-       struct ldp_igp_sync_hello hello;
-
-       sequence++;
-
-       hello.proto = ZEBRA_ROUTE_LDP;
-       hello.sequence = sequence;
-
-       zclient_send_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE,
-               (const uint8_t *) &hello, sizeof(hello));
-
-       ldp_sync_zebra_start_hello_timer();
-
-       return (0);
-}
-
 static void
 ldp_sync_zebra_init(void)
 {
        ldp_sync_zebra_send_announce();
-
-       ldp_sync_zebra_start_hello_timer();
 }
 
-
 static int
 ldp_zebra_send_mpls_labels(int cmd, struct kroute *kr)
 {
@@ -272,7 +279,10 @@ ldp_zebra_send_mpls_labels(int cmd, struct kroute *kr)
        znh->label_num = 1;
        znh->labels[0] = kr->remote_label;
 
-       return zebra_send_mpls_labels(zclient, cmd, &zl);
+       if (zebra_send_mpls_labels(zclient, cmd, &zl) == ZCLIENT_SEND_FAILURE)
+               return -1;
+
+       return 0;
 }
 
 int
@@ -293,7 +303,8 @@ kmpw_add(struct zapi_pw *zpw)
        debug_zebra_out("pseudowire %s nexthop %s (add)",
            zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
 
-       return (zebra_send_pw(zclient, ZEBRA_PW_ADD, zpw));
+       return zebra_send_pw(zclient, ZEBRA_PW_ADD, zpw)
+              == ZCLIENT_SEND_FAILURE;
 }
 
 int
@@ -302,7 +313,8 @@ kmpw_del(struct zapi_pw *zpw)
        debug_zebra_out("pseudowire %s nexthop %s (del)",
            zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
 
-       return (zebra_send_pw(zclient, ZEBRA_PW_DELETE, zpw));
+       return zebra_send_pw(zclient, ZEBRA_PW_DELETE, zpw)
+              == ZCLIENT_SEND_FAILURE;
 }
 
 int
@@ -312,7 +324,8 @@ kmpw_set(struct zapi_pw *zpw)
            zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop),
            zpw->local_label, zpw->remote_label);
 
-       return (zebra_send_pw(zclient, ZEBRA_PW_SET, zpw));
+       return zebra_send_pw(zclient, ZEBRA_PW_SET, zpw)
+              == ZCLIENT_SEND_FAILURE;
 }
 
 int
@@ -321,7 +334,8 @@ kmpw_unset(struct zapi_pw *zpw)
        debug_zebra_out("pseudowire %s nexthop %s (unset)",
            zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
 
-       return (zebra_send_pw(zclient, ZEBRA_PW_UNSET, zpw));
+       return zebra_send_pw(zclient, ZEBRA_PW_UNSET, zpw)
+              == ZCLIENT_SEND_FAILURE;
 }
 
 void
index d6da45c8624ab9b71ae7ea2a819b1353fc2ad717..83e93ebbbc52715295bfd53700088f0a28d44d36 100644 (file)
@@ -625,6 +625,7 @@ main_dispatch_lde(struct thread *thread)
        struct imsg      imsg;
        ssize_t          n;
        int              shut = 0;
+       struct zapi_rlfa_response *rlfa_labels;
 
        iev->ev_read = NULL;
 
@@ -691,6 +692,15 @@ main_dispatch_lde(struct thread *thread)
                                fatalx("IMSG_ACL_CHECK imsg with wrong len");
                        ldp_acl_reply(iev, (struct acl_check *)imsg.data);
                        break;
+               case IMSG_RLFA_LABELS:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct zapi_rlfa_response)) {
+                               log_warnx("%s: wrong imsg len", __func__);
+                               break;
+                       }
+                       rlfa_labels = imsg.data;
+                       ldp_zebra_send_rlfa_labels(rlfa_labels);
+                       break;
                default:
                        log_debug("%s: error handling imsg %d", __func__,
                            imsg.hdr.type);
index f8a94b4e2a50d08d651a6210966ab0109149d8f7..beb625d8a26bf08133c8ea573e8d9479afb1b7ec 100644 (file)
@@ -157,7 +157,10 @@ enum imsg_type {
        IMSG_FILTER_UPDATE,
        IMSG_NBR_SHUTDOWN,
        IMSG_LDP_SYNC_IF_STATE_REQUEST,
-       IMSG_LDP_SYNC_IF_STATE_UPDATE
+       IMSG_LDP_SYNC_IF_STATE_UPDATE,
+       IMSG_RLFA_REG,
+       IMSG_RLFA_UNREG_ALL,
+       IMSG_RLFA_LABELS,
 };
 
 struct ldpd_init {
@@ -373,6 +376,7 @@ struct tnbr {
        union ldpd_addr          addr;
        int                      state;
        uint16_t                 pw_count;
+       uint32_t                 rlfa_count;
        uint8_t                  flags;
        QOBJ_FIELDS
 };
@@ -875,6 +879,8 @@ extern char                  ctl_sock_path[MAXPATHLEN];
 void            ldp_zebra_init(struct thread_master *);
 void            ldp_zebra_destroy(void);
 int             ldp_sync_zebra_send_state_update(struct ldp_igp_sync_if_state *);
+int             ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response *
+                   rlfa_labels);
 
 /* compatibility */
 #ifndef __OpenBSD__
index ffc1d17f517aaa788cf30aded91740b29e1f5f17..6a5a0750bd007f2cc281ea33c4ca80f44b064ae2 100644 (file)
@@ -27,6 +27,7 @@
 #include "control.h"
 #include "log.h"
 #include "ldp_debug.h"
+#include "rlfa.h"
 
 #include <lib/log.h>
 #include "memory.h"
@@ -49,6 +50,7 @@ struct ldpd_conf      *leconf;
 struct ldpd_sysdep      sysdep;
 #endif
 
+static struct imsgev    iev_main_data;
 static struct imsgev   *iev_main, *iev_main_sync;
 static struct imsgev   *iev_lde;
 #ifdef __OpenBSD__
@@ -124,8 +126,8 @@ ldpe(void)
                        &iev_main->ev_read);
        iev_main->handler_write = ldp_write_handler;
 
-       if ((iev_main_sync = calloc(1, sizeof(struct imsgev))) == NULL)
-               fatal(NULL);
+       memset(&iev_main_data, 0, sizeof(iev_main_data));
+       iev_main_sync = &iev_main_data;
        imsg_init(&iev_main_sync->ibuf, LDPD_FD_SYNC);
 
        /* create base configuration */
@@ -231,7 +233,6 @@ ldpe_shutdown(void)
        if (iev_lde)
                free(iev_lde);
        free(iev_main);
-       free(iev_main_sync);
        free(pkt_ptr);
 
        log_info("ldp engine exiting");
@@ -298,7 +299,11 @@ ldpe_dispatch_main(struct thread *thread)
        int                      n, shut = 0;
        struct ldp_access       *laccess;
        struct ldp_igp_sync_if_state_req *ldp_sync_if_state_req;
-       
+       struct ldp_rlfa_node     *rnode, *rntmp;
+       struct ldp_rlfa_client   *rclient;
+       struct zapi_rlfa_request *rlfa_req;
+       struct zapi_rlfa_igp     *rlfa_igp;
+
        iev->ev_read = NULL;
 
        if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
@@ -569,6 +574,44 @@ ldpe_dispatch_main(struct thread *thread)
                        ldp_sync_if_state_req = imsg.data;
                        ldp_sync_fsm_state_req(ldp_sync_if_state_req);
                        break;
+               case IMSG_RLFA_REG:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct zapi_rlfa_request)) {
+                               log_warnx("%s: wrong imsg len", __func__);
+                               break;
+                       }
+                       rlfa_req = imsg.data;
+
+                       rnode = rlfa_node_find(&rlfa_req->destination,
+                                              rlfa_req->pq_address);
+                       if (!rnode)
+                               rnode = rlfa_node_new(&rlfa_req->destination,
+                                                     rlfa_req->pq_address);
+                       rclient = rlfa_client_find(rnode, &rlfa_req->igp);
+                       if (rclient)
+                               /* RLFA already registered - do nothing */
+                               break;
+                       rclient = rlfa_client_new(rnode, &rlfa_req->igp);
+                       ldpe_rlfa_init(rclient);
+                       break;
+               case IMSG_RLFA_UNREG_ALL:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct zapi_rlfa_igp)) {
+                               log_warnx("%s: wrong imsg len", __func__);
+                               break;
+                       }
+                       rlfa_igp = imsg.data;
+
+                       RB_FOREACH_SAFE (rnode, ldp_rlfa_node_head,
+                                        &rlfa_node_tree, rntmp) {
+                               rclient = rlfa_client_find(rnode, rlfa_igp);
+                               if (!rclient)
+                                       continue;
+
+                               ldpe_rlfa_exit(rclient);
+                               rlfa_client_del(rclient);
+                       }
+                       break;
                default:
                        log_debug("ldpe_dispatch_main: error handling imsg %d",
                            imsg.hdr.type);
index 19030175884e94479e26863a83e5463723274404..1aaad41a10edf48fb4d7f4c82d6691ca016a13c8 100644 (file)
@@ -22,6 +22,7 @@
 #include "ldpe.h"
 #include "lde.h"
 #include "log.h"
+#include "printfrr.h"
 
 #include <lib/log.h>
 
@@ -44,12 +45,12 @@ vlog(int pri, const char *fmt, va_list ap)
 
        switch (ldpd_process) {
        case PROC_LDE_ENGINE:
-               vsnprintf(buf, sizeof(buf), fmt, ap);
+               vsnprintfrr(buf, sizeof(buf), fmt, ap);
                lde_imsg_compose_parent_sync(IMSG_LOG, pri, buf,
                    strlen(buf) + 1);
                break;
        case PROC_LDP_ENGINE:
-               vsnprintf(buf, sizeof(buf), fmt, ap);
+               vsnprintfrr(buf, sizeof(buf), fmt, ap);
                ldpe_imsg_compose_parent_sync(IMSG_LOG, pri, buf,
                    strlen(buf) + 1);
                break;
diff --git a/ldpd/rlfa.c b/ldpd/rlfa.c
new file mode 100644 (file)
index 0000000..697ec08
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2020  NetDEF, Inc.
+ *                     Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "ldpd.h"
+#include "lde.h"
+#include "ldpe.h"
+#include "log.h"
+#include "ldp_debug.h"
+#include "rlfa.h"
+
+#include <lib/log.h>
+
+struct ldp_rlfa_node_head rlfa_node_tree;
+
+static int ldp_rlfa_client_compare(const struct ldp_rlfa_client *a,
+                                  const struct ldp_rlfa_client *b)
+{
+       if (a->igp.vrf_id < b->igp.vrf_id)
+               return -1;
+       if (a->igp.vrf_id > b->igp.vrf_id)
+               return 1;
+
+       if (a->igp.protocol < b->igp.protocol)
+               return -1;
+       if (a->igp.protocol > b->igp.protocol)
+               return 1;
+
+       if (a->igp.isis.spf.tree_id < b->igp.isis.spf.tree_id)
+               return -1;
+       if (a->igp.isis.spf.tree_id > b->igp.isis.spf.tree_id)
+               return 1;
+
+       if (a->igp.isis.spf.level < b->igp.isis.spf.level)
+               return -1;
+       if (a->igp.isis.spf.level > b->igp.isis.spf.level)
+               return 1;
+
+       return 0;
+}
+RB_GENERATE(ldp_rlfa_client_head, ldp_rlfa_client, entry,
+           ldp_rlfa_client_compare)
+
+static int ldp_rlfa_node_compare(const struct ldp_rlfa_node *a,
+                                const struct ldp_rlfa_node *b)
+{
+       if (ntohl(a->pq_address.s_addr) < ntohl(b->pq_address.s_addr))
+               return -1;
+       if (ntohl(a->pq_address.s_addr) > ntohl(b->pq_address.s_addr))
+               return 1;
+
+       return prefix_cmp(&a->destination, &b->destination);
+}
+RB_GENERATE(ldp_rlfa_node_head, ldp_rlfa_node, entry, ldp_rlfa_node_compare)
+
+struct ldp_rlfa_client *rlfa_client_new(struct ldp_rlfa_node *rnode,
+                                       struct zapi_rlfa_igp *igp)
+{
+       struct ldp_rlfa_client *rclient;
+
+       if ((rclient = calloc(1, sizeof(*rclient))) == NULL)
+               fatal(__func__);
+
+       rclient->igp = *igp;
+       rclient->node = rnode;
+       RB_INSERT(ldp_rlfa_client_head, &rnode->clients, rclient);
+
+       return rclient;
+}
+
+void rlfa_client_del(struct ldp_rlfa_client *rclient)
+{
+       struct ldp_rlfa_node *rnode = rclient->node;
+
+       RB_REMOVE(ldp_rlfa_client_head, &rnode->clients, rclient);
+       free(rclient);
+
+       /* Delete RLFA node if it's empty. */
+       if (RB_EMPTY(ldp_rlfa_client_head, &rnode->clients))
+               rlfa_node_del(rnode);
+}
+
+struct ldp_rlfa_client *rlfa_client_find(struct ldp_rlfa_node *rnode,
+                                        struct zapi_rlfa_igp *igp)
+{
+       struct ldp_rlfa_client rclient;
+
+       rclient.igp = *igp;
+       return RB_FIND(ldp_rlfa_client_head, &rnode->clients, &rclient);
+}
+
+struct ldp_rlfa_node *rlfa_node_new(const struct prefix *destination,
+                                   struct in_addr pq_address)
+{
+       struct ldp_rlfa_node *rnode;
+
+       if ((rnode = calloc(1, sizeof(*rnode))) == NULL)
+               fatal(__func__);
+
+       rnode->destination = *destination;
+       rnode->pq_address = pq_address;
+       rnode->pq_label = MPLS_INVALID_LABEL;
+       RB_INIT(ldp_rlfa_client_head, &rnode->clients);
+       RB_INSERT(ldp_rlfa_node_head, &rlfa_node_tree, rnode);
+
+       return rnode;
+}
+
+void rlfa_node_del(struct ldp_rlfa_node *rnode)
+{
+       /* Delete RLFA clients. */
+       while (!RB_EMPTY(ldp_rlfa_client_head, &rnode->clients)) {
+               struct ldp_rlfa_client *rclient;
+
+               rclient = RB_ROOT(ldp_rlfa_client_head, &rnode->clients);
+               rlfa_client_del(rclient);
+       }
+
+       RB_REMOVE(ldp_rlfa_node_head, &rlfa_node_tree, rnode);
+       free(rnode);
+}
+
+struct ldp_rlfa_node *rlfa_node_find(const struct prefix *destination,
+                                    struct in_addr pq_address)
+{
+       struct ldp_rlfa_node rnode = {};
+
+       rnode.destination = *destination;
+       rnode.pq_address = pq_address;
+       return RB_FIND(ldp_rlfa_node_head, &rlfa_node_tree, &rnode);
+}
+
+void lde_rlfa_client_send(struct ldp_rlfa_client *rclient)
+{
+       struct ldp_rlfa_node            *rnode = rclient->node;
+       struct zapi_rlfa_response        rlfa_labels = {};
+       struct fec                       fec;
+       struct fec_node                 *fn;
+       struct fec_nh                   *fnh;
+       int                              i = 0;
+
+       /* Fill in inner label (allocated by PQ node). */
+       rlfa_labels.igp = rclient->igp;
+       rlfa_labels.destination = rnode->destination;
+       rlfa_labels.pq_label = rnode->pq_label;
+
+       /* Fill in outer label(s) (allocated by the nexthop routers). */
+       fec.type = FEC_TYPE_IPV4;
+       fec.u.ipv4.prefix = rnode->pq_address;
+       fec.u.ipv4.prefixlen = IPV4_MAX_BITLEN;
+       fn = (struct fec_node *)fec_find(&ft, &fec);
+       if (!fn)
+               return;
+       LIST_FOREACH(fnh, &fn->nexthops, entry) {
+               if (fnh->remote_label == NO_LABEL)
+                       continue;
+
+               rlfa_labels.nexthops[i].family = fnh->af;
+               switch (fnh->af) {
+               case AF_INET:
+                       rlfa_labels.nexthops[i].gate.ipv4 = fnh->nexthop.v4;
+                       break;
+               case AF_INET6:
+                       rlfa_labels.nexthops[i].gate.ipv6 = fnh->nexthop.v6;
+                       break;
+               default:
+                       continue;
+               }
+               rlfa_labels.nexthops[i].label = fnh->remote_label;
+               i++;
+       }
+       rlfa_labels.nexthop_num = i;
+
+       lde_imsg_compose_parent(IMSG_RLFA_LABELS, 0, &rlfa_labels,
+                               sizeof(rlfa_labels));
+}
+
+void lde_rlfa_label_update(const struct fec *fec)
+{
+       struct ldp_rlfa_node *rnode;
+
+       if (fec->type != FEC_TYPE_IPV4
+           || fec->u.ipv4.prefixlen != IPV4_MAX_BITLEN)
+               return;
+
+       /*
+        * TODO: use an rb-tree lookup to restrict the iteration to the RLFAs
+        * that were effectivelly affected by the label update.
+        */
+       RB_FOREACH (rnode, ldp_rlfa_node_head, &rlfa_node_tree) {
+               struct ldp_rlfa_client *rclient;
+
+               if (!IPV4_ADDR_SAME(&rnode->pq_address, &fec->u.ipv4.prefix))
+                       continue;
+
+               RB_FOREACH (rclient, ldp_rlfa_client_head, &rnode->clients)
+                       lde_rlfa_client_send(rclient);
+       }
+}
+
+void lde_rlfa_check(struct ldp_rlfa_client *rclient)
+{
+       struct lde_nbr *ln;
+       struct lde_map *me;
+       struct fec fec;
+       union ldpd_addr pq_address = {};
+
+       pq_address.v4 = rclient->node->pq_address;
+       ln = lde_nbr_find_by_addr(AF_INET, &pq_address);
+       if (!ln)
+               return;
+
+       lde_prefix2fec(&rclient->node->destination, &fec);
+       me = (struct lde_map *)fec_find(&ln->recv_map, &fec);
+       if (!me)
+               return;
+
+       rclient->node->pq_label = me->map.label;
+       lde_rlfa_client_send(rclient);
+}
+
+/*
+ * Check if there's any registered RLFA client for this prefix/neighbor (PQ
+ * node) and notify about the updated label.
+ */
+void lde_rlfa_update_clients(struct fec *fec, struct lde_nbr *ln,
+                            uint32_t label)
+{
+       struct prefix            rlfa_dest;
+       struct ldp_rlfa_node    *rnode;
+
+       lde_fec2prefix(fec, &rlfa_dest);
+       rnode = rlfa_node_find(&rlfa_dest, ln->id);
+       if (rnode) {
+               struct ldp_rlfa_client *rclient;
+
+               rnode->pq_label = label;
+               RB_FOREACH (rclient, ldp_rlfa_client_head, &rnode->clients)
+                       lde_rlfa_client_send(rclient);
+       } else
+               lde_rlfa_label_update(fec);
+}
+
+void ldpe_rlfa_init(struct ldp_rlfa_client *rclient)
+{
+       struct tnbr *tnbr;
+       union ldpd_addr pq_address = {};
+
+       pq_address.v4 = rclient->node->pq_address;
+       tnbr = tnbr_find(leconf, AF_INET, &pq_address);
+       if (tnbr == NULL) {
+               tnbr = tnbr_new(AF_INET, &pq_address);
+               tnbr_update(tnbr);
+               RB_INSERT(tnbr_head, &leconf->tnbr_tree, tnbr);
+       }
+
+       tnbr->rlfa_count++;
+}
+
+void ldpe_rlfa_exit(struct ldp_rlfa_client *rclient)
+{
+       struct tnbr *tnbr;
+       union ldpd_addr pq_address = {};
+
+       pq_address.v4 = rclient->node->pq_address;
+       tnbr = tnbr_find(leconf, AF_INET, &pq_address);
+       if (tnbr) {
+               tnbr->rlfa_count--;
+               tnbr_check(leconf, tnbr);
+       }
+}
diff --git a/ldpd/rlfa.h b/ldpd/rlfa.h
new file mode 100644 (file)
index 0000000..fe67917
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020  NetDEF, Inc.
+ *                     Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LDPD_RLFA_H_
+#define _LDPD_RLFA_H_
+
+#include "openbsd-tree.h"
+#include "zclient.h"
+
+struct ldp_rlfa_client {
+       RB_ENTRY(ldp_rlfa_client) entry;
+
+       /* IGP instance data. */
+       struct zapi_rlfa_igp igp;
+
+       /* Backpointer to RLFA node. */
+       struct ldp_rlfa_node *node;
+};
+RB_HEAD(ldp_rlfa_client_head, ldp_rlfa_client);
+RB_PROTOTYPE(ldp_rlfa_client_head, ldp_rlfa_client, entry,
+            ldp_rlfa_client_compare);
+
+struct ldp_rlfa_node {
+       RB_ENTRY(ldp_rlfa_node) entry;
+
+       /* Destination prefix. */
+       struct prefix destination;
+
+       /* PQ node address. */
+       struct in_addr pq_address;
+
+       /* RLFA clients. */
+       struct ldp_rlfa_client_head clients;
+
+       /* Label allocated by the PQ node to the RLFA destination. */
+       mpls_label_t pq_label;
+};
+RB_HEAD(ldp_rlfa_node_head, ldp_rlfa_node);
+RB_PROTOTYPE(ldp_rlfa_node_head, ldp_rlfa_node, entry, ldp_rlfa_node_compare);
+
+extern struct ldp_rlfa_node_head rlfa_node_tree;
+
+/* prototypes */
+struct          ldp_rlfa_client *rlfa_client_new(struct ldp_rlfa_node *rnode,
+                   struct zapi_rlfa_igp *igp);
+void            rlfa_client_del(struct ldp_rlfa_client *rclient);
+struct ldp_rlfa_client *rlfa_client_find(struct ldp_rlfa_node *rnode,
+                   struct zapi_rlfa_igp *igp);
+struct ldp_rlfa_node *rlfa_node_new(const struct prefix *destination,
+                   struct in_addr pq_address);
+void rlfa_node_del(struct ldp_rlfa_node *rnode);
+struct ldp_rlfa_node *rlfa_node_find(const struct prefix *destination,
+                   struct in_addr pq_address);
+void            lde_rlfa_check(struct ldp_rlfa_client *rclient);
+void            lde_rlfa_client_send(struct ldp_rlfa_client *rclient);
+void            lde_rlfa_label_update(const struct fec *fec);
+void            lde_rlfa_update_clients(struct fec *fec, struct lde_nbr *ln,
+                   uint32_t label);
+void            ldpe_rlfa_init(struct ldp_rlfa_client *rclient);
+void            ldpe_rlfa_exit(struct ldp_rlfa_client *rclient);
+
+#endif /* _LDPD_RLFA_H_ */
index 2058d2596a6d7e992eca01817bf4bb86948bd2dc..d89d18341d0a315c67bf9e11cef4887970a44478 100644 (file)
@@ -36,6 +36,7 @@ ldpd_libldp_a_SOURCES = \
        ldpd/notification.c \
        ldpd/packet.c \
        ldpd/pfkey.c \
+       ldpd/rlfa.c \
        ldpd/socket.c \
        ldpd/util.c \
        # end
@@ -53,6 +54,7 @@ noinst_HEADERS += \
        ldpd/ldpd.h \
        ldpd/ldpe.h \
        ldpd/log.h \
+       ldpd/rlfa.h \
        # end
 
 ldpd_ldpd_SOURCES = ldpd/ldpd.c
index 1a37b348f8a33034580379463c43cdfde0af89bd..cdf700860170f29c0d009f5dc6ca2b06a507fd65 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -405,7 +405,7 @@ void bfd_client_sendmsg(struct zclient *zclient, int command,
                        vrf_id_t vrf_id)
 {
        struct stream *s;
-       int ret;
+       enum zclient_send_status ret;
 
        /* Check socket. */
        if (!zclient || zclient->sock < 0) {
@@ -426,7 +426,7 @@ void bfd_client_sendmsg(struct zclient *zclient, int command,
 
        ret = zclient_send_message(zclient);
 
-       if (ret < 0) {
+       if (ret == ZCLIENT_SEND_FAILURE) {
                if (bfd_debug)
                        zlog_debug(
                                "bfd_client_sendmsg %ld: zclient_send_message() failed",
@@ -542,7 +542,7 @@ int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args)
        stream_putw_at(s, 0, stream_get_endp(s));
 
        /* Send message to zebra. */
-       if (zclient_send_message(zc) == -1) {
+       if (zclient_send_message(zc) == ZCLIENT_SEND_FAILURE) {
                if (bfd_debug)
                        zlog_debug("%s: zclient_send_message failed", __func__);
                return -1;
index 87110157f6eb8e851d1856c5bc606348dd35e9c1..b34fa7ff3eb7091b857001bcbcd23ed4d7cf3a6e 100644 (file)
@@ -49,6 +49,8 @@
 #include "northbound_cli.h"
 #include "network.h"
 
+#include "frrscript.h"
+
 DEFINE_MTYPE_STATIC(LIB, HOST, "Host config")
 DEFINE_MTYPE(LIB, COMPLETION, "Completion item")
 
@@ -863,6 +865,30 @@ enum node_type node_parent(enum node_type node)
        case BFD_PROFILE_NODE:
                ret = BFD_NODE;
                break;
+       case SR_TRAFFIC_ENG_NODE:
+               ret = SEGMENT_ROUTING_NODE;
+               break;
+       case SR_SEGMENT_LIST_NODE:
+               ret = SR_TRAFFIC_ENG_NODE;
+               break;
+       case SR_POLICY_NODE:
+               ret = SR_TRAFFIC_ENG_NODE;
+               break;
+       case SR_CANDIDATE_DYN_NODE:
+               ret = SR_POLICY_NODE;
+               break;
+       case PCEP_NODE:
+               ret = SR_TRAFFIC_ENG_NODE;
+               break;
+       case PCEP_PCE_CONFIG_NODE:
+               ret = PCEP_NODE;
+               break;
+       case PCEP_PCE_NODE:
+               ret = PCEP_NODE;
+               break;
+       case PCEP_PCC_NODE:
+               ret = PCEP_NODE;
+               break;
        default:
                ret = CONFIG_NODE;
                break;
@@ -2279,6 +2305,31 @@ done:
        return CMD_SUCCESS;
 }
 
+#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING)
+DEFUN(script,
+      script_cmd,
+      "script SCRIPT",
+      "Test command - execute a script\n"
+      "Script name (same as filename in /etc/frr/scripts/\n")
+{
+       struct prefix p;
+
+       (void)str2prefix("1.2.3.4/24", &p);
+
+       struct frrscript *fs = frrscript_load(argv[1]->arg, NULL);
+
+       if (fs == NULL) {
+               vty_out(vty, "Script '/etc/frr/scripts/%s.lua' not found\n",
+                       argv[1]->arg);
+       } else {
+               int ret = frrscript_call(fs, NULL);
+               vty_out(vty, "Script result: %d\n", ret);
+       }
+
+       return CMD_SUCCESS;
+}
+#endif
+
 /* Set config filename.  Called from vty.c */
 void host_config_set(const char *filename)
 {
@@ -2373,6 +2424,10 @@ void cmd_init(int terminal)
                install_element(VIEW_NODE, &echo_cmd);
                install_element(VIEW_NODE, &autocomplete_cmd);
                install_element(VIEW_NODE, &find_cmd);
+#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING)
+               install_element(VIEW_NODE, &script_cmd);
+#endif
+
 
                install_element(ENABLE_NODE, &config_end_cmd);
                install_element(ENABLE_NODE, &config_disable_cmd);
index bb007b08683af952007481eaa1c04da5df104a4c..bfe64a7235af7c8be0b77c6b9a34e9d44e829a71 100644 (file)
@@ -145,6 +145,15 @@ enum node_type {
        PROTOCOL_NODE,           /* protocol filtering node */
        MPLS_NODE,               /* MPLS config node */
        PW_NODE,                 /* Pseudowire config node */
+       SEGMENT_ROUTING_NODE,    /* Segment routing root node */
+       SR_TRAFFIC_ENG_NODE,     /* SR Traffic Engineering node */
+       SR_SEGMENT_LIST_NODE,    /* SR segment list config node */
+       SR_POLICY_NODE,          /* SR policy config node */
+       SR_CANDIDATE_DYN_NODE,   /* SR dynamic candidate path config node */
+       PCEP_NODE,               /* PCEP node */
+       PCEP_PCE_CONFIG_NODE,    /* PCE shared configuration node */
+       PCEP_PCE_NODE,           /* PCE configuration node */
+       PCEP_PCC_NODE,           /* PCC configuration node */
        VTY_NODE,                /* Vty node. */
        FPM_NODE,                /* Dataplane FPM node. */
        LINK_PARAMS_NODE,       /* Link-parameters node */
@@ -530,7 +539,9 @@ extern int cmd_execute_command(vector, struct vty *,
                               const struct cmd_element **, int);
 extern int cmd_execute_command_strict(vector, struct vty *,
                                      const struct cmd_element **);
-extern void cmd_init(int);
+extern void cmd_init(int terminal);
+extern void cmd_init_config_callbacks(void (*start_config_cb)(void),
+                                     void (*end_config_cb)(void));
 extern void cmd_terminate(void);
 extern void cmd_exit(struct vty *vty);
 extern int cmd_list_cmds(struct vty *vty, int do_permute);
index 217a60d8881651796b848deea65066dcbd04559f..70ef8e9bc80255eb3a4996a2464d0fdf611de2ed 100644 (file)
@@ -279,6 +279,29 @@ extern "C" {
 
 #define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
 
+/* Some insane macros to count number of varargs to a functionlike macro */
+#define PP_ARG_N( \
+          _1,  _2,  _3,  _4,  _5,  _6,  _7,  _8,  _9, _10, \
+         _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
+         _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
+         _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
+         _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
+         _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
+         _61, _62, _63, N, ...) N
+
+#define PP_RSEQ_N()                                        \
+         62, 61, 60,                                       \
+         59, 58, 57, 56, 55, 54, 53, 52, 51, 50,           \
+         49, 48, 47, 46, 45, 44, 43, 42, 41, 40,           \
+         39, 38, 37, 36, 35, 34, 33, 32, 31, 30,           \
+         29, 28, 27, 26, 25, 24, 23, 22, 21, 20,           \
+         19, 18, 17, 16, 15, 14, 13, 12, 11, 10,           \
+          9,  8,  7,  6,  5,  4,  3,  2,  1,  0
+
+#define PP_NARG_(...)    PP_ARG_N(__VA_ARGS__)    
+#define PP_NARG(...)     PP_NARG_(_, ##__VA_ARGS__, PP_RSEQ_N())
+
+
 /* sigh. this is so ugly, it overflows and wraps to being nice again.
  *
  * printfrr() supports "%Ld" for <int64_t>, whatever that is typedef'd to.
index 7b923da17761e1bfa529b53569a743b71d436772..691da495cf13dd318fa08fdef23c87defb1fed63 100644 (file)
@@ -121,8 +121,12 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json)
 
        if (code) {
                ref = log_ref_get(code);
-               if (!ref)
+               if (!ref) {
+                       if (top)
+                               json_object_free(top);
+                       list_delete(&errlist);
                        return;
+               }
                listnode_add(errlist, ref);
        }
 
index a89b595e8746104bc2b892c65e244703edd9da04..4e95431cea211e75a19225acf0b1ded5e0535a95 100644 (file)
@@ -132,6 +132,8 @@ struct ferr {
 #define VTYSH_FRR_END       0x0FFFFFFF
 #define WATCHFRR_FERR_START 0x10000001
 #define WATCHFRR_FERR_END   0x10FFFFFF
+#define PATH_FERR_START     0x11000001
+#define PATH_FERR_END       0x11FFFFFF
 #define ZEBRA_FERR_START    0xF1000001
 #define ZEBRA_FERR_END      0xF1FFFFFF
 #define END_FERR            0xFFFFFFFF
index 623fb945276e2ea741d2c3e236741966b1c46a56..091a5197f6af3a73422af8b44cf31c3bee5c640e 100644 (file)
@@ -176,6 +176,60 @@ enum yang_prefix_list_action {
        YPLA_PERMIT = 1,
 };
 
+struct acl_dup_args {
+       /** Access list type ("ipv4", "ipv6" or "mac"). */
+       const char *ada_type;
+       /** Access list name. */
+       const char *ada_name;
+
+#define ADA_MAX_VALUES 4
+       /** Entry XPath for value. */
+       const char *ada_xpath[ADA_MAX_VALUES];
+       /** Entry value to match. */
+       const char *ada_value[ADA_MAX_VALUES];
+
+       /** Duplicated entry found in list? */
+       bool ada_found;
+
+       /** (Optional) Already existing `dnode`. */
+       const struct lyd_node *ada_entry_dnode;
+};
+
+/**
+ * Check for duplicated entries using the candidate configuration.
+ *
+ * \param vty so we can get the candidate config.
+ * \param ada the arguments to check.
+ */
+bool acl_is_dup(const struct lyd_node *dnode, struct acl_dup_args *ada);
+
+struct plist_dup_args {
+       /** Access list type ("ipv4" or "ipv6"). */
+       const char *pda_type;
+       /** Access list name. */
+       const char *pda_name;
+
+#define PDA_MAX_VALUES 4
+       /** Entry XPath for value. */
+       const char *pda_xpath[PDA_MAX_VALUES];
+       /** Entry value to match. */
+       const char *pda_value[PDA_MAX_VALUES];
+
+       /** Duplicated entry found in list? */
+       bool pda_found;
+
+       /** (Optional) Already existing `dnode`. */
+       const struct lyd_node *pda_entry_dnode;
+};
+
+/**
+ * Check for duplicated entries using the candidate configuration.
+ *
+ * \param vty so we can get the candidate config.
+ * \param pda the arguments to check.
+ */
+bool plist_is_dup(const struct lyd_node *dnode, struct plist_dup_args *pda);
+
 /* filter_cli.c */
 struct lyd_node;
 struct vty;
index a8230f3a9a7f86d9b8fa20fc0ea352bcadcdfa0d..54b6cda9a59752a37be493b4ef66fed29960e748 100644 (file)
@@ -162,9 +162,35 @@ DEFPY_YANG(
        "Wildcard bits\n")
 {
        int64_t sseq;
+       struct acl_dup_args ada = {};
        char xpath[XPATH_MAXLEN];
        char xpath_entry[XPATH_MAXLEN + 128];
 
+       /*
+        * Backward compatibility: don't complain about duplicated values,
+        * just silently accept.
+        */
+       if (seq_str == NULL) {
+               ada.ada_type = "ipv4";
+               ada.ada_name = name;
+               if (host_str && mask_str == NULL) {
+                       ada.ada_xpath[0] = "./host";
+                       ada.ada_value[0] = host_str;
+               } else if (host_str && mask_str) {
+                       ada.ada_xpath[0] = "./network/address";
+                       ada.ada_value[0] = host_str;
+                       ada.ada_xpath[1] = "./network/mask";
+                       ada.ada_value[1] = mask_str;
+               } else {
+                       ada.ada_xpath[0] = "./source-any";
+                       ada.ada_value[0] = "true";
+               }
+
+               /* Duplicated entry without sequence, just quit. */
+               if (acl_is_dup(vty->candidate_config->dnode, &ada))
+                       return CMD_SUCCESS;
+       }
+
        /*
         * Create the access-list first, so we can generate sequence if
         * none given (backward compatibility).
@@ -270,10 +296,58 @@ DEFPY_YANG(
        "Destination address to match\n"
        "Any destination host\n")
 {
+       int idx = 0;
        int64_t sseq;
+       struct acl_dup_args ada = {};
        char xpath[XPATH_MAXLEN];
        char xpath_entry[XPATH_MAXLEN + 128];
 
+       /*
+        * Backward compatibility: don't complain about duplicated values,
+        * just silently accept.
+        */
+       if (seq_str == NULL) {
+               ada.ada_type = "ipv4";
+               ada.ada_name = name;
+               if (src_str && src_mask_str == NULL) {
+                       ada.ada_xpath[idx] = "./host";
+                       ada.ada_value[idx] = src_str;
+                       idx++;
+               } else if (src_str && src_mask_str) {
+                       ada.ada_xpath[idx] = "./network/address";
+                       ada.ada_value[idx] = src_str;
+                       idx++;
+                       ada.ada_xpath[idx] = "./network/mask";
+                       ada.ada_value[idx] = src_mask_str;
+                       idx++;
+               } else {
+                       ada.ada_xpath[idx] = "./source-any";
+                       ada.ada_value[idx] = "true";
+                       idx++;
+               }
+
+               if (dst_str && dst_mask_str == NULL) {
+                       ada.ada_xpath[idx] = "./destination-host";
+                       ada.ada_value[idx] = dst_str;
+                       idx++;
+               } else if (dst_str && dst_mask_str) {
+                       ada.ada_xpath[idx] = "./destination-network/address";
+                       ada.ada_value[idx] = dst_str;
+                       idx++;
+                       ada.ada_xpath[idx] = "./destination-network/mask";
+                       ada.ada_value[idx] = dst_mask_str;
+                       idx++;
+               } else {
+                       ada.ada_xpath[idx] = "./destination-any";
+                       ada.ada_value[idx] = "true";
+                       idx++;
+               }
+
+               /* Duplicated entry without sequence, just quit. */
+               if (acl_is_dup(vty->candidate_config->dnode, &ada))
+                       return CMD_SUCCESS;
+       }
+
        /*
         * Create the access-list first, so we can generate sequence if
         * none given (backward compatibility).
@@ -419,9 +493,35 @@ DEFPY_YANG(
        "Match any IPv4\n")
 {
        int64_t sseq;
+       struct acl_dup_args ada = {};
        char xpath[XPATH_MAXLEN];
        char xpath_entry[XPATH_MAXLEN + 128];
 
+       /*
+        * Backward compatibility: don't complain about duplicated values,
+        * just silently accept.
+        */
+       if (seq_str == NULL) {
+               ada.ada_type = "ipv4";
+               ada.ada_name = name;
+
+               if (prefix_str) {
+                       ada.ada_xpath[0] = "./ipv4-prefix";
+                       ada.ada_value[0] = prefix_str;
+                       if (exact) {
+                               ada.ada_xpath[1] = "./ipv4-exact-match";
+                               ada.ada_value[1] = "true";
+                       }
+               } else {
+                       ada.ada_xpath[0] = "./any";
+                       ada.ada_value[0] = "true";
+               }
+
+               /* Duplicated entry without sequence, just quit. */
+               if (acl_is_dup(vty->candidate_config->dnode, &ada))
+                       return CMD_SUCCESS;
+       }
+
        /*
         * Create the access-list first, so we can generate sequence if
         * none given (backward compatibility).
@@ -590,9 +690,35 @@ DEFPY_YANG(
        "Match any IPv6\n")
 {
        int64_t sseq;
+       struct acl_dup_args ada = {};
        char xpath[XPATH_MAXLEN];
        char xpath_entry[XPATH_MAXLEN + 128];
 
+       /*
+        * Backward compatibility: don't complain about duplicated values,
+        * just silently accept.
+        */
+       if (seq_str == NULL) {
+               ada.ada_type = "ipv6";
+               ada.ada_name = name;
+
+               if (prefix_str) {
+                       ada.ada_xpath[0] = "./ipv6-prefix";
+                       ada.ada_value[0] = prefix_str;
+                       if (exact) {
+                               ada.ada_xpath[1] = "./ipv6-exact-match";
+                               ada.ada_value[1] = "true";
+                       }
+               } else {
+                       ada.ada_xpath[0] = "./any";
+                       ada.ada_value[0] = "true";
+               }
+
+               /* Duplicated entry without sequence, just quit. */
+               if (acl_is_dup(vty->candidate_config->dnode, &ada))
+                       return CMD_SUCCESS;
+       }
+
        /*
         * Create the access-list first, so we can generate sequence if
         * none given (backward compatibility).
@@ -765,9 +891,31 @@ DEFPY_YANG(
        "Match any MAC address\n")
 {
        int64_t sseq;
+       struct acl_dup_args ada = {};
        char xpath[XPATH_MAXLEN];
        char xpath_entry[XPATH_MAXLEN + 128];
 
+       /*
+        * Backward compatibility: don't complain about duplicated values,
+        * just silently accept.
+        */
+       if (seq_str == NULL) {
+               ada.ada_type = "mac";
+               ada.ada_name = name;
+
+               if (mac_str) {
+                       ada.ada_xpath[0] = "./mac";
+                       ada.ada_value[0] = mac_str;
+               } else {
+                       ada.ada_xpath[0] = "./any";
+                       ada.ada_value[0] = "true";
+               }
+
+               /* Duplicated entry without sequence, just quit. */
+               if (acl_is_dup(vty->candidate_config->dnode, &ada))
+                       return CMD_SUCCESS;
+       }
+
        /*
         * Create the access-list first, so we can generate sequence if
         * none given (backward compatibility).
@@ -1171,9 +1319,44 @@ DEFPY_YANG(
        "Maximum prefix length\n")
 {
        int64_t sseq;
+       int arg_idx = 0;
+       struct plist_dup_args pda = {};
        char xpath[XPATH_MAXLEN];
        char xpath_entry[XPATH_MAXLEN + 128];
 
+       /*
+        * Backward compatibility: don't complain about duplicated values,
+        * just silently accept.
+        */
+       if (seq_str == NULL) {
+               pda.pda_type = "ipv4";
+               pda.pda_name = name;
+               if (prefix_str) {
+                       pda.pda_xpath[arg_idx] = "./ipv4-prefix";
+                       pda.pda_value[arg_idx] = prefix_str;
+                       arg_idx++;
+                       if (ge_str) {
+                               pda.pda_xpath[arg_idx] =
+                                       "./ipv4-prefix-length-greater-or-equal";
+                               pda.pda_value[arg_idx] = ge_str;
+                               arg_idx++;
+                       }
+                       if (le_str) {
+                               pda.pda_xpath[arg_idx] =
+                                       "./ipv4-prefix-length-lesser-or-equal";
+                               pda.pda_value[arg_idx] = le_str;
+                               arg_idx++;
+                       }
+               } else {
+                       pda.pda_xpath[0] = "./any";
+                       pda.pda_value[0] = "";
+               }
+
+               /* Duplicated entry without sequence, just quit. */
+               if (plist_is_dup(vty->candidate_config->dnode, &pda))
+                       return CMD_SUCCESS;
+       }
+
        /*
         * Create the prefix-list first, so we can generate sequence if
         * none given (backward compatibility).
@@ -1331,9 +1514,44 @@ DEFPY_YANG(
        "Minimum prefix length\n")
 {
        int64_t sseq;
+       int arg_idx = 0;
+       struct plist_dup_args pda = {};
        char xpath[XPATH_MAXLEN];
        char xpath_entry[XPATH_MAXLEN + 128];
 
+       /*
+        * Backward compatibility: don't complain about duplicated values,
+        * just silently accept.
+        */
+       if (seq_str == NULL) {
+               pda.pda_type = "ipv6";
+               pda.pda_name = name;
+               if (prefix_str) {
+                       pda.pda_xpath[arg_idx] = "./ipv6-prefix";
+                       pda.pda_value[arg_idx] = prefix_str;
+                       arg_idx++;
+                       if (ge_str) {
+                               pda.pda_xpath[arg_idx] =
+                                       "./ipv6-prefix-length-greater-or-equal";
+                               pda.pda_value[arg_idx] = ge_str;
+                               arg_idx++;
+                       }
+                       if (le_str) {
+                               pda.pda_xpath[arg_idx] =
+                                       "./ipv6-prefix-length-lesser-or-equal";
+                               pda.pda_value[arg_idx] = le_str;
+                               arg_idx++;
+                       }
+               } else {
+                       pda.pda_xpath[0] = "./any";
+                       pda.pda_value[0] = "";
+               }
+
+               /* Duplicated entry without sequence, just quit. */
+               if (plist_is_dup(vty->candidate_config->dnode, &pda))
+                       return CMD_SUCCESS;
+       }
+
        /*
         * Create the prefix-list first, so we can generate sequence if
         * none given (backward compatibility).
index 1d522bdbec56b9c890aa57b6a5dc069a709c8b28..2007b37cdfe1cd6d971c37af097f5bd608b32257 100644 (file)
@@ -133,6 +133,220 @@ static void cisco_unset_addr_mask(struct in_addr *addr, struct in_addr *mask)
        mask->s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
 }
 
+static int _acl_is_dup(const struct lyd_node *dnode, void *arg)
+{
+       struct acl_dup_args *ada = arg;
+       int idx;
+
+       /* This entry is the caller, so skip it. */
+       if (ada->ada_entry_dnode
+           && ada->ada_entry_dnode == dnode)
+               return YANG_ITER_CONTINUE;
+
+       /* Check if all values match. */
+       for (idx = 0; idx < ADA_MAX_VALUES; idx++) {
+               /* No more values. */
+               if (ada->ada_xpath[idx] == NULL)
+                       break;
+
+               /* Not same type, just skip it. */
+               if (!yang_dnode_exists(dnode, ada->ada_xpath[idx]))
+                       return YANG_ITER_CONTINUE;
+
+               /* Check if different value. */
+               if (strcmp(yang_dnode_get_string(dnode, ada->ada_xpath[idx]),
+                          ada->ada_value[idx]))
+                       return YANG_ITER_CONTINUE;
+       }
+
+       ada->ada_found = true;
+
+       return YANG_ITER_STOP;
+}
+
+bool acl_is_dup(const struct lyd_node *dnode, struct acl_dup_args *ada)
+{
+       ada->ada_found = false;
+
+       yang_dnode_iterate(
+               _acl_is_dup, ada, dnode,
+               "/frr-filter:lib/access-list[type='%s'][name='%s']/entry",
+               ada->ada_type, ada->ada_name);
+
+       return ada->ada_found;
+}
+
+static bool acl_cisco_is_dup(const struct lyd_node *dnode)
+{
+       const struct lyd_node *entry_dnode =
+               yang_dnode_get_parent(dnode, "entry");
+       struct acl_dup_args ada = {};
+       int idx = 0, arg_idx = 0;
+       static const char *cisco_entries[] = {
+               "./host",
+               "./network/address",
+               "./network/mask",
+               "./source-any",
+               "./destination-host",
+               "./destination-network/address",
+               "./destination-network/mask",
+               "./destination-any",
+               NULL
+       };
+
+       /* Initialize. */
+       ada.ada_type = "ipv4";
+       ada.ada_name = yang_dnode_get_string(entry_dnode, "../name");
+       ada.ada_entry_dnode = entry_dnode;
+
+       /* Load all values/XPaths. */
+       while (cisco_entries[idx] != NULL) {
+               if (!yang_dnode_exists(entry_dnode, cisco_entries[idx])) {
+                       idx++;
+                       continue;
+               }
+
+               ada.ada_xpath[arg_idx] = cisco_entries[idx];
+               ada.ada_value[arg_idx] =
+                       yang_dnode_get_string(entry_dnode, cisco_entries[idx]);
+               arg_idx++;
+               idx++;
+       }
+
+       return acl_is_dup(entry_dnode, &ada);
+}
+
+static bool acl_zebra_is_dup(const struct lyd_node *dnode,
+                            enum yang_access_list_type type)
+{
+       const struct lyd_node *entry_dnode =
+               yang_dnode_get_parent(dnode, "entry");
+       struct acl_dup_args ada = {};
+       int idx = 0, arg_idx = 0;
+       static const char *zebra_entries[] = {
+               "./ipv4-prefix",
+               "./ipv4-exact-match",
+               "./ipv6-prefix",
+               "./ipv6-exact-match",
+               "./mac",
+               "./any",
+               NULL
+       };
+
+       /* Initialize. */
+       switch (type) {
+       case YALT_IPV4:
+               ada.ada_type = "ipv4";
+               break;
+       case YALT_IPV6:
+               ada.ada_type = "ipv6";
+               break;
+       case YALT_MAC:
+               ada.ada_type = "mac";
+               break;
+       }
+       ada.ada_name = yang_dnode_get_string(entry_dnode, "../name");
+       ada.ada_entry_dnode = entry_dnode;
+
+       /* Load all values/XPaths. */
+       while (zebra_entries[idx] != NULL) {
+               if (!yang_dnode_exists(entry_dnode, zebra_entries[idx])) {
+                       idx++;
+                       continue;
+               }
+
+               ada.ada_xpath[arg_idx] = zebra_entries[idx];
+               ada.ada_value[arg_idx] =
+                       yang_dnode_get_string(entry_dnode, zebra_entries[idx]);
+               arg_idx++;
+               idx++;
+       }
+
+       return acl_is_dup(entry_dnode, &ada);
+}
+
+static int _plist_is_dup(const struct lyd_node *dnode, void *arg)
+{
+       struct plist_dup_args *pda = arg;
+       int idx;
+
+       /* This entry is the caller, so skip it. */
+       if (pda->pda_entry_dnode
+           && pda->pda_entry_dnode == dnode)
+               return YANG_ITER_CONTINUE;
+
+       /* Check if all values match. */
+       for (idx = 0; idx < PDA_MAX_VALUES; idx++) {
+               /* No more values. */
+               if (pda->pda_xpath[idx] == NULL)
+                       break;
+
+               /* Not same type, just skip it. */
+               if (!yang_dnode_exists(dnode, pda->pda_xpath[idx]))
+                       return YANG_ITER_CONTINUE;
+
+               /* Check if different value. */
+               if (strcmp(yang_dnode_get_string(dnode, pda->pda_xpath[idx]),
+                          pda->pda_value[idx]))
+                       return YANG_ITER_CONTINUE;
+       }
+
+       pda->pda_found = true;
+
+       return YANG_ITER_STOP;
+}
+
+bool plist_is_dup(const struct lyd_node *dnode, struct plist_dup_args *pda)
+{
+       pda->pda_found = false;
+
+       yang_dnode_iterate(
+               _plist_is_dup, pda, dnode,
+               "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry",
+               pda->pda_type, pda->pda_name);
+
+       return pda->pda_found;
+}
+
+static bool plist_is_dup_nb(const struct lyd_node *dnode)
+{
+       const struct lyd_node *entry_dnode =
+               yang_dnode_get_parent(dnode, "entry");
+       struct plist_dup_args pda = {};
+       int idx = 0, arg_idx = 0;
+       static const char *entries[] = {
+               "./ipv4-prefix",
+               "./ipv4-prefix-length-greater-or-equal",
+               "./ipv4-prefix-length-lesser-or-equal",
+               "./ipv6-prefix",
+               "./ipv6-prefix-length-greater-or-equal",
+               "./ipv6-prefix-length-lesser-or-equal",
+               "./any",
+               NULL
+       };
+
+       /* Initialize. */
+       pda.pda_type = yang_dnode_get_string(entry_dnode, "../type");
+       pda.pda_name = yang_dnode_get_string(entry_dnode, "../name");
+       pda.pda_entry_dnode = entry_dnode;
+
+       /* Load all values/XPaths. */
+       while (entries[idx] != NULL) {
+               if (!yang_dnode_exists(entry_dnode, entries[idx])) {
+                       idx++;
+                       continue;
+               }
+
+               pda.pda_xpath[arg_idx] = entries[idx];
+               pda.pda_value[arg_idx] =
+                       yang_dnode_get_string(entry_dnode, entries[idx]);
+               arg_idx++;
+               idx++;
+       }
+
+       return plist_is_dup(entry_dnode, &pda);
+}
+
 /*
  * XPath: /frr-filter:lib/access-list
  */
@@ -290,6 +504,19 @@ lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
        struct filter_zebra *fz;
        struct filter *f;
 
+       /* Don't allow duplicated values. */
+       if (args->event == NB_EV_VALIDATE) {
+               if (acl_zebra_is_dup(
+                           args->dnode,
+                           yang_dnode_get_enum(args->dnode, "../../type"))) {
+                       snprintfrr(args->errmsg, args->errmsg_len,
+                                  "duplicated access list value: %s",
+                                  yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
+               return NB_OK;
+       }
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -330,6 +557,19 @@ lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args)
        struct filter_zebra *fz;
        struct filter *f;
 
+       /* Don't allow duplicated values. */
+       if (args->event == NB_EV_VALIDATE) {
+               if (acl_zebra_is_dup(
+                           args->dnode,
+                           yang_dnode_get_enum(args->dnode, "../../type"))) {
+                       snprintfrr(args->errmsg, args->errmsg_len,
+                                  "duplicated access list value: %s",
+                                  yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
+               return NB_OK;
+       }
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -369,6 +609,17 @@ lib_access_list_entry_host_modify(struct nb_cb_modify_args *args)
        struct filter_cisco *fc;
        struct filter *f;
 
+       /* Don't allow duplicated values. */
+       if (args->event == NB_EV_VALIDATE) {
+               if (acl_cisco_is_dup(args->dnode)) {
+                       snprintfrr(args->errmsg, args->errmsg_len,
+                                  "duplicated access list value: %s",
+                                  yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
+               return NB_OK;
+       }
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -410,6 +661,17 @@ lib_access_list_entry_network_address_modify(struct nb_cb_modify_args *args)
        struct filter_cisco *fc;
        struct filter *f;
 
+       /* Don't allow duplicated values. */
+       if (args->event == NB_EV_VALIDATE) {
+               if (acl_cisco_is_dup(args->dnode)) {
+                       snprintfrr(args->errmsg, args->errmsg_len,
+                                  "duplicated access list value: %s",
+                                  yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
+               return NB_OK;
+       }
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -432,6 +694,17 @@ lib_access_list_entry_network_mask_modify(struct nb_cb_modify_args *args)
        struct filter_cisco *fc;
        struct filter *f;
 
+       /* Don't allow duplicated values. */
+       if (args->event == NB_EV_VALIDATE) {
+               if (acl_cisco_is_dup(args->dnode)) {
+                       snprintfrr(args->errmsg, args->errmsg_len,
+                                  "duplicated access list value: %s",
+                                  yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
+               return NB_OK;
+       }
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -454,6 +727,17 @@ lib_access_list_entry_source_any_create(struct nb_cb_create_args *args)
        struct filter_cisco *fc;
        struct filter *f;
 
+       /* Don't allow duplicated values. */
+       if (args->event == NB_EV_VALIDATE) {
+               if (acl_cisco_is_dup(args->dnode)) {
+                       snprintfrr(args->errmsg, args->errmsg_len,
+                                  "duplicated access list value: %s",
+                                  yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
+               return NB_OK;
+       }
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -495,6 +779,17 @@ static int lib_access_list_entry_destination_host_modify(
        struct filter_cisco *fc;
        struct filter *f;
 
+       /* Don't allow duplicated values. */
+       if (args->event == NB_EV_VALIDATE) {
+               if (acl_cisco_is_dup(args->dnode)) {
+                       snprintfrr(args->errmsg, args->errmsg_len,
+                                  "duplicated access list value: %s",
+                                  yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
+               return NB_OK;
+       }
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -537,6 +832,17 @@ static int lib_access_list_entry_destination_network_address_modify(
        struct filter_cisco *fc;
        struct filter *f;
 
+       /* Don't allow duplicated values. */
+       if (args->event == NB_EV_VALIDATE) {
+               if (acl_cisco_is_dup(args->dnode)) {
+                       snprintfrr(args->errmsg, args->errmsg_len,
+                                  "duplicated access list value: %s",
+                                  yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
+               return NB_OK;
+       }
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -559,6 +865,17 @@ static int lib_access_list_entry_destination_network_mask_modify(
        struct filter_cisco *fc;
        struct filter *f;
 
+       /* Don't allow duplicated values. */
+       if (args->event == NB_EV_VALIDATE) {
+               if (acl_cisco_is_dup(args->dnode)) {
+                       snprintfrr(args->errmsg, args->errmsg_len,
+                                  "duplicated access list value: %s",
+                                  yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
+               return NB_OK;
+       }
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -581,6 +898,17 @@ static int lib_access_list_entry_destination_any_create(
        struct filter_cisco *fc;
        struct filter *f;
 
+       /* Don't allow duplicated values. */
+       if (args->event == NB_EV_VALIDATE) {
+               if (acl_cisco_is_dup(args->dnode)) {
+                       snprintfrr(args->errmsg, args->errmsg_len,
+                                  "duplicated access list value: %s",
+                                  yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
+               return NB_OK;
+       }
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -623,6 +951,19 @@ static int lib_access_list_entry_any_create(struct nb_cb_create_args *args)
        struct filter *f;
        int type;
 
+       /* Don't allow duplicated values. */
+       if (args->event == NB_EV_VALIDATE) {
+               if (acl_zebra_is_dup(
+                           args->dnode,
+                           yang_dnode_get_enum(args->dnode, "../../type"))) {
+                       snprintfrr(args->errmsg, args->errmsg_len,
+                                  "duplicated access list value: %s",
+                                  yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
+               return NB_OK;
+       }
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -817,15 +1158,12 @@ lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
        struct prefix p;
 
        if (args->event == NB_EV_VALIDATE) {
-               /*
-                * TODO: validate prefix_entry_dup_check() passes.
-                *
-                * This needs to be implemented using YANG lyd_node
-                * navigation, because the `priv` data structures are not
-                * available at `NB_EV_VALIDATE` phase. An easier
-                * alternative would be mark `ipvx-prefix` as unique
-                * (see RFC 7950, Section 7.8.3. The list "unique" Statement).
-                */
+               if (plist_is_dup_nb(args->dnode)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "duplicated prefix list value: %s",
+                                yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
                return NB_OK;
        }
 
@@ -888,6 +1226,16 @@ static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify(
            prefix_list_length_validate(args) != NB_OK)
                return NB_ERR_VALIDATION;
 
+       if (args->event == NB_EV_VALIDATE) {
+               if (plist_is_dup_nb(args->dnode)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "duplicated prefix list value: %s",
+                                yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
+               return NB_OK;
+       }
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -937,6 +1285,16 @@ static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
            prefix_list_length_validate(args) != NB_OK)
                return NB_ERR_VALIDATION;
 
+       if (args->event == NB_EV_VALIDATE) {
+               if (plist_is_dup_nb(args->dnode)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "duplicated prefix list value: %s",
+                                yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
+               return NB_OK;
+       }
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -982,6 +1340,16 @@ static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args)
        struct prefix_list_entry *ple;
        int type;
 
+       if (args->event == NB_EV_VALIDATE) {
+               if (plist_is_dup_nb(args->dnode)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "duplicated prefix list value: %s",
+                                yang_dnode_get_string(args->dnode, NULL));
+                       return NB_ERR_VALIDATION;
+               }
+               return NB_OK;
+       }
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
index 9f9cf8c1f69ecc06a578353915b1a9b03f611ca9..d8aaa3aa3c6d9abeefff0ad3f966029232e6813d 100644 (file)
  * This file defines the lua interface into
  * FRRouting.
  *
- * Copyright (C) 2016 Cumulus Networks, Inc.
- * Donald Sharp
+ * Copyright (C) 2016-2019 Cumulus Networks, Inc.
+ * Donald Sharp, Quentin Young
  *
- * This file is part of FRRouting (FRR).
+ * 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.
  *
- * FRR is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2, or (at your option) any later version.
- *
- * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- * details.
+ * 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 FRR; see the file COPYING.  If not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * 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>
 
-#if defined(HAVE_LUA)
+#ifdef HAVE_SCRIPTING
+
 #include "prefix.h"
 #include "frrlua.h"
 #include "log.h"
+#include "buffer.h"
+
+/* Lua stuff */
 
-static int lua_zlog_debug(lua_State *L)
+/*
+ * FRR convenience functions.
+ *
+ * This section has convenience functions used to make interacting with the Lua
+ * stack easier.
+ */
+
+int frrlua_table_get_integer(lua_State *L, const char *key)
 {
-       int debug_lua = 1;
-       const char *string = lua_tostring(L, 1);
+       int result;
 
-       if (debug_lua)
-               zlog_debug("%s", string);
+       lua_pushstring(L, key);
+       lua_gettable(L, -2);
 
-       return 0;
+       result = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+
+       return result;
 }
 
-const char *get_string(lua_State *L, const char *key)
+/*
+ * Encoders.
+ *
+ * This section has functions that convert internal FRR datatypes into Lua
+ * datatypes.
+ */
+
+void lua_pushprefix(lua_State *L, const struct prefix *prefix)
 {
-       const char *str;
+       char buffer[PREFIX_STRLEN];
 
-       lua_pushstring(L, key);
-       lua_gettable(L, -2);
+       lua_newtable(L);
+       lua_pushstring(L, prefix2str(prefix, buffer, PREFIX_STRLEN));
+       lua_setfield(L, -2, "network");
+       lua_pushinteger(L, prefix->prefixlen);
+       lua_setfield(L, -2, "length");
+       lua_pushinteger(L, prefix->family);
+       lua_setfield(L, -2, "family");
+}
 
-       str = (const char *)lua_tostring(L, -1);
+void *lua_toprefix(lua_State *L, int idx)
+{
+       struct prefix *p = XCALLOC(MTYPE_TMP, sizeof(struct prefix));
+
+       lua_getfield(L, idx, "network");
+       (void)str2prefix(lua_tostring(L, -1), p);
        lua_pop(L, 1);
 
-       return str;
+       return p;
 }
 
-int get_integer(lua_State *L, const char *key)
+void lua_pushinterface(lua_State *L, const struct interface *ifp)
 {
-       int result;
+       lua_newtable(L);
+       lua_pushstring(L, ifp->name);
+       lua_setfield(L, -2, "name");
+       lua_pushinteger(L, ifp->ifindex);
+       lua_setfield(L, -2, "ifindex");
+       lua_pushinteger(L, ifp->status);
+       lua_setfield(L, -2, "status");
+       lua_pushinteger(L, ifp->flags);
+       lua_setfield(L, -2, "flags");
+       lua_pushinteger(L, ifp->metric);
+       lua_setfield(L, -2, "metric");
+       lua_pushinteger(L, ifp->speed);
+       lua_setfield(L, -2, "speed");
+       lua_pushinteger(L, ifp->mtu);
+       lua_setfield(L, -2, "mtu");
+       lua_pushinteger(L, ifp->mtu6);
+       lua_setfield(L, -2, "mtu6");
+       lua_pushinteger(L, ifp->bandwidth);
+       lua_setfield(L, -2, "bandwidth");
+       lua_pushinteger(L, ifp->link_ifindex);
+       lua_setfield(L, -2, "link_ifindex");
+       lua_pushinteger(L, ifp->ll_type);
+       lua_setfield(L, -2, "linklayer_type");
+}
 
-       lua_pushstring(L, key);
-       lua_gettable(L, -2);
+void *lua_tointerface(lua_State *L, int idx)
+{
+       struct interface *ifp = XCALLOC(MTYPE_TMP, sizeof(struct interface));
 
-       result = lua_tointeger(L, -1);
+       lua_getfield(L, idx, "name");
+       strlcpy(ifp->name, lua_tostring(L, -1), sizeof(ifp->name));
+       lua_pop(L, 1);
+       lua_getfield(L, idx, "ifindex");
+       ifp->ifindex = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, idx, "status");
+       ifp->status = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, idx, "flags");
+       ifp->flags = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, idx, "metric");
+       ifp->metric = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, idx, "speed");
+       ifp->speed = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, idx, "mtu");
+       ifp->mtu = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, idx, "mtu6");
+       ifp->mtu6 = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, idx, "bandwidth");
+       ifp->bandwidth = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, idx, "link_ifindex");
+       ifp->link_ifindex = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, idx, "linklayer_type");
+       ifp->ll_type = lua_tointeger(L, -1);
        lua_pop(L, 1);
 
-       return result;
+       return ifp;
 }
 
-static void *lua_alloc(void *ud, void *ptr, size_t osize,
-                      size_t nsize)
+void lua_pushinaddr(lua_State *L, const struct in_addr *addr)
 {
-       (void)ud;  (void)osize;  /* not used */
-       if (nsize == 0) {
-               free(ptr);
-               return NULL;
-       } else
-               return realloc(ptr, nsize);
+       char buf[INET_ADDRSTRLEN];
+       inet_ntop(AF_INET, addr, buf, sizeof(buf));
+
+       lua_newtable(L);
+       lua_pushinteger(L, addr->s_addr);
+       lua_setfield(L, -2, "value");
+       lua_pushstring(L, buf);
+       lua_setfield(L, -2, "string");
 }
 
-lua_State *lua_initialize(const char *file)
+void *lua_toinaddr(lua_State *L, int idx)
 {
-       int status;
-       lua_State *L = lua_newstate(lua_alloc, NULL);
+       struct in_addr *inaddr = XCALLOC(MTYPE_TMP, sizeof(struct in_addr));
 
-       zlog_debug("Newstate: %p", L);
-       luaL_openlibs(L);
-       zlog_debug("Opened lib");
-       status = luaL_loadfile(L, file);
-       if (status) {
-               zlog_debug("Failure to open %s %d", file, status);
-               lua_close(L);
-               return NULL;
-       }
+       lua_getfield(L, idx, "value");
+       inaddr->s_addr = lua_tointeger(L, -1);
+       lua_pop(L, 1);
 
-       lua_pcall(L, 0, LUA_MULTRET, 0);
-       zlog_debug("Setting global function");
-       lua_pushcfunction(L, lua_zlog_debug);
-       lua_setglobal(L, "zlog_debug");
+       return inaddr;
+}
+
+
+void lua_pushin6addr(lua_State *L, const struct in6_addr *addr)
+{
+       char buf[INET6_ADDRSTRLEN];
+       inet_ntop(AF_INET6, addr, buf, sizeof(buf));
+
+       lua_newtable(L);
+       lua_pushlstring(L, (const char *)addr->s6_addr, 16);
+       lua_setfield(L, -2, "value");
+       lua_pushstring(L, buf);
+       lua_setfield(L, -2, "string");
+}
+
+void *lua_toin6addr(lua_State *L, int idx)
+{
+       struct in6_addr *in6addr = XCALLOC(MTYPE_TMP, sizeof(struct in6_addr));
+
+       lua_getfield(L, idx, "string");
+       inet_pton(AF_INET6, lua_tostring(L, -1), in6addr);
+       lua_pop(L, 1);
 
-       return L;
+       return in6addr;
 }
 
-void lua_setup_prefix_table(lua_State *L, const struct prefix *prefix)
+void lua_pushsockunion(lua_State *L, const union sockunion *su)
 {
-       char buffer[100];
+       char buf[SU_ADDRSTRLEN];
+       sockunion2str(su, buf, sizeof(buf));
 
        lua_newtable(L);
-       lua_pushstring(L, prefix2str(prefix, buffer, 100));
-       lua_setfield(L, -2, "route");
-       lua_pushinteger(L, prefix->family);
-       lua_setfield(L, -2, "family");
-       lua_setglobal(L, "prefix");
+       lua_pushlstring(L, (const char *)sockunion_get_addr(su),
+                       sockunion_get_addrlen(su));
+       lua_setfield(L, -2, "value");
+       lua_pushstring(L, buf);
+       lua_setfield(L, -2, "string");
 }
 
-enum lua_rm_status lua_run_rm_rule(lua_State *L, const char *rule)
+void *lua_tosockunion(lua_State *L, int idx)
 {
-       int status;
+       union sockunion *su = XCALLOC(MTYPE_TMP, sizeof(union sockunion));
+
+       lua_getfield(L, idx, "string");
+       str2sockunion(lua_tostring(L, -1), su);
+
+       return su;
+}
 
-       lua_getglobal(L, rule);
-       status = lua_pcall(L, 0, 1, 0);
-       if (status) {
-               zlog_debug("Executing Failure with function: %s: %d",
-                          rule, status);
-               return LUA_RM_FAILURE;
+void lua_pushtimet(lua_State *L, const time_t *time)
+{
+       lua_pushinteger(L, *time);
+}
+
+void *lua_totimet(lua_State *L, int idx)
+{
+       time_t *t = XCALLOC(MTYPE_TMP, sizeof(time_t));
+
+       *t = lua_tointeger(L, idx);
+
+       return t;
+}
+
+void lua_pushintegerp(lua_State *L, const long long *num)
+{
+       lua_pushinteger(L, *num);
+}
+
+void *lua_tointegerp(lua_State *L, int idx)
+{
+       int isnum;
+       long long *num = XCALLOC(MTYPE_TMP, sizeof(long long));
+
+       *num = lua_tonumberx(L, idx, &isnum);
+       assert(isnum);
+
+       return num;
+}
+
+void *lua_tostringp(lua_State *L, int idx)
+{
+       char *string = XSTRDUP(MTYPE_TMP, lua_tostring(L, idx));
+
+       return string;
+}
+
+/*
+ * Logging.
+ *
+ * Lua-compatible wrappers for FRR logging functions.
+ */
+static const char *frrlua_log_thunk(lua_State *L)
+{
+       int nargs;
+
+       nargs = lua_gettop(L);
+       assert(nargs == 1);
+
+       return lua_tostring(L, 1);
+}
+
+static int frrlua_log_debug(lua_State *L)
+{
+       zlog_debug("%s", frrlua_log_thunk(L));
+       return 0;
+}
+
+static int frrlua_log_info(lua_State *L)
+{
+       zlog_info("%s", frrlua_log_thunk(L));
+       return 0;
+}
+
+static int frrlua_log_notice(lua_State *L)
+{
+       zlog_notice("%s", frrlua_log_thunk(L));
+       return 0;
+}
+
+static int frrlua_log_warn(lua_State *L)
+{
+       zlog_warn("%s", frrlua_log_thunk(L));
+       return 0;
+}
+
+static int frrlua_log_error(lua_State *L)
+{
+       zlog_err("%s", frrlua_log_thunk(L));
+       return 0;
+}
+
+static const luaL_Reg log_funcs[] = {
+       {"debug", frrlua_log_debug},
+       {"info", frrlua_log_info},
+       {"notice", frrlua_log_notice},
+       {"warn", frrlua_log_warn},
+       {"error", frrlua_log_error},
+       {},
+};
+
+void frrlua_export_logging(lua_State *L)
+{
+       lua_newtable(L);
+       luaL_setfuncs(L, log_funcs, 0);
+       lua_setglobal(L, "log");
+}
+
+/*
+ * Debugging.
+ */
+
+char *frrlua_stackdump(lua_State *L)
+{
+       int top = lua_gettop(L);
+
+       char tmpbuf[64];
+       struct buffer *buf = buffer_new(4098);
+
+       for (int i = 1; i <= top; i++) {
+               int t = lua_type(L, i);
+
+               switch (t) {
+               case LUA_TSTRING: /* strings */
+                       snprintf(tmpbuf, sizeof(tmpbuf), "\"%s\"\n",
+                                lua_tostring(L, i));
+                       buffer_putstr(buf, tmpbuf);
+                       break;
+               case LUA_TBOOLEAN: /* booleans */
+                       snprintf(tmpbuf, sizeof(tmpbuf), "%s\n",
+                                lua_toboolean(L, i) ? "true" : "false");
+                       buffer_putstr(buf, tmpbuf);
+                       break;
+               case LUA_TNUMBER: /* numbers */
+                       snprintf(tmpbuf, sizeof(tmpbuf), "%g\n",
+                                lua_tonumber(L, i));
+                       buffer_putstr(buf, tmpbuf);
+                       break;
+               default: /* other values */
+                       snprintf(tmpbuf, sizeof(tmpbuf), "%s\n",
+                                lua_typename(L, t));
+                       buffer_putstr(buf, tmpbuf);
+                       break;
+               }
        }
 
-       status = lua_tonumber(L, -1);
-       return status;
+       char *result = XSTRDUP(MTYPE_TMP, buffer_getstr(buf));
+
+       buffer_free(buf);
+
+       return result;
 }
-#endif
+
+#endif /* HAVE_SCRIPTING */
index 40c7a67b8970c117b193ff6431f0285bcddfe4be..8e52931e503ab5c6f457ff1823ba119daefa544b 100644 (file)
 /*
- * This file defines the lua interface into
- * FRRouting.
+ * Copyright (C) 2016-2019 Cumulus Networks, Inc.
+ * Donald Sharp, Quentin Young
  *
- * Copyright (C) 2016 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 file is part of FRRouting (FRR).
- *
- * FRR is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2, or (at your option) any later version.
- *
- * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- * details.
+ * 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 FRR; see the file COPYING.  If not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * 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 __LUA_H__
-#define __LUA_H__
+#ifndef __FRRLUA_H__
+#define __FRRLUA_H__
+
+#include <zebra.h>
+
+#ifdef HAVE_SCRIPTING
 
-#if defined(HAVE_LUA)
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
 
-#include "lua.h"
-#include "lualib.h"
-#include "lauxlib.h"
+#include "prefix.h"
+#include "frrscript.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /*
- * These functions are helper functions that
- * try to glom some of the lua_XXX functionality
- * into what we actually need, instead of having
- * to make multiple calls to set up what
- * we want
+ * Converts a prefix to a Lua value and pushes it on the stack.
+ */
+void lua_pushprefix(lua_State *L, const struct prefix *prefix);
+
+/*
+ * Converts the Lua value at idx to a prefix.
+ *
+ * Returns:
+ *    struct prefix allocated with MTYPE_TMP
+ */
+void *lua_toprefix(lua_State *L, int idx);
+
+/*
+ * Converts an interface to a Lua value and pushes it on the stack.
+ */
+void lua_pushinterface(lua_State *L, const struct interface *ifp);
+
+/*
+ * Converts the Lua value at idx to an interface.
+ *
+ * Returns:
+ *    struct interface allocated with MTYPE_TMP. This interface is not hooked
+ *    to anything, nor is it inserted in the global interface tree.
+ */
+void *lua_tointerface(lua_State *L, int idx);
+
+/*
+ * Converts an in_addr to a Lua value and pushes it on the stack.
+ */
+void lua_pushinaddr(lua_State *L, const struct in_addr *addr);
+
+/*
+ * Converts the Lua value at idx to an in_addr.
+ *
+ * Returns:
+ *    struct in_addr allocated with MTYPE_TMP.
+ */
+void *lua_toinaddr(lua_State *L, int idx);
+
+/*
+ * Converts an in6_addr to a Lua value and pushes it on the stack.
  */
-enum lua_rm_status {
-       /*
-        * Script function run failure.  This will translate into a
-        * deny
-        */
-       LUA_RM_FAILURE = 0,
-       /*
-        * No Match was found for the route map function
-        */
-       LUA_RM_NOMATCH,
-       /*
-        * Match was found but no changes were made to the
-        * incoming data.
-        */
-       LUA_RM_MATCH,
-       /*
-        * Match was found and data was modified, so
-        * figure out what changed
-        */
-       LUA_RM_MATCH_AND_CHANGE,
-};
+void lua_pushin6addr(lua_State *L, const struct in6_addr *addr);
 
 /*
- * Open up the lua.scr file and parse
- * initial global values, if any.
+ * Converts the Lua value at idx to an in6_addr.
+ *
+ * Returns:
+ *    struct in6_addr allocated with MTYPE_TMP.
  */
-lua_State *lua_initialize(const char *file);
+void *lua_toin6addr(lua_State *L, int idx);
 
-void lua_setup_prefix_table(lua_State *L, const struct prefix *prefix);
+/*
+ * Converts a time_t to a Lua value and pushes it on the stack.
+ */
+void lua_pushtimet(lua_State *L, const time_t *time);
 
-enum lua_rm_status lua_run_rm_rule(lua_State *L, const char *rule);
+/*
+ * Converts the Lua value at idx to a time_t.
+ *
+ * Returns:
+ *    time_t allocated with MTYPE_TMP.
+ */
+void *lua_totimet(lua_State *L, int idx);
 
 /*
- * Get particular string/integer information
- * from a table.  It is *assumed* that
- * the table has already been selected
+ * Converts a sockunion to a Lua value and pushes it on the stack.
  */
-const char *get_string(lua_State *L, const char *key);
-int get_integer(lua_State *L, const char *key);
+void lua_pushsockunion(lua_State *L, const union sockunion *su);
+
+/*
+ * Converts the Lua value at idx to a sockunion.
+ *
+ * Returns:
+ *    sockunion allocated with MTYPE_TMP.
+ */
+void *lua_tosockunion(lua_State *L, int idx);
+
+/*
+ * Converts an int to a Lua value and pushes it on the stack.
+ */
+void lua_pushintegerp(lua_State *L, const long long *num);
+
+/*
+ * Converts the Lua value at idx to an int.
+ *
+ * Returns:
+ *    int allocated with MTYPE_TMP.
+ */
+void *lua_tointegerp(lua_State *L, int idx);
+
+/*
+ * Pop string.
+ *
+ * Sets *string to a copy of the string at the top of the stack. The copy is
+ * allocated with MTYPE_TMP and the caller is responsible for freeing it.
+ */
+void *lua_tostringp(lua_State *L, int idx);
+
+/*
+ * Retrieve an integer from table on the top of the stack.
+ *
+ * key
+ *    Key of string value in table
+ */
+int frrlua_table_get_integer(lua_State *L, const char *key);
+
+/*
+ * Exports a new table containing bindings to FRR zlog functions into the
+ * global namespace.
+ *
+ * From Lua, these functions may be accessed as:
+ *
+ * - log.debug()
+ * - log.info()
+ * - log.warn()
+ * - log.error()
+ *
+ * They take a single string argument.
+ */
+void frrlua_export_logging(lua_State *L);
+
+/*
+ * Dump Lua stack to a string.
+ *
+ * Return value must be freed with XFREE(MTYPE_TMP, ...);
+ */
+char *frrlua_stackdump(lua_State *L);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif
-#endif
+#endif /* HAVE_SCRIPTING */
+
+#endif /* __FRRLUA_H__ */
diff --git a/lib/frrscript.c b/lib/frrscript.c
new file mode 100644 (file)
index 0000000..a3de474
--- /dev/null
@@ -0,0 +1,272 @@
+/* Scripting foo
+ * Copyright (C) 2020  NVIDIA Corporation
+ * Quentin Young
+ *
+ * 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>
+
+#ifdef HAVE_SCRIPTING
+
+#include <stdarg.h>
+#include <lua.h>
+
+#include "frrscript.h"
+#include "frrlua.h"
+#include "memory.h"
+#include "hash.h"
+#include "log.h"
+
+
+DEFINE_MTYPE_STATIC(LIB, SCRIPT, "Scripting");
+
+/* Codecs */
+
+struct frrscript_codec frrscript_codecs_lib[] = {
+       {.typename = "integer",
+        .encoder = (encoder_func)lua_pushintegerp,
+        .decoder = lua_tointegerp},
+       {.typename = "string",
+        .encoder = (encoder_func)lua_pushstring,
+        .decoder = lua_tostringp},
+       {.typename = "prefix",
+        .encoder = (encoder_func)lua_pushprefix,
+        .decoder = lua_toprefix},
+       {.typename = "interface",
+        .encoder = (encoder_func)lua_pushinterface,
+        .decoder = lua_tointerface},
+       {.typename = "in_addr",
+        .encoder = (encoder_func)lua_pushinaddr,
+        .decoder = lua_toinaddr},
+       {.typename = "in6_addr",
+        .encoder = (encoder_func)lua_pushin6addr,
+        .decoder = lua_toin6addr},
+       {.typename = "sockunion",
+        .encoder = (encoder_func)lua_pushsockunion,
+        .decoder = lua_tosockunion},
+       {.typename = "time_t",
+        .encoder = (encoder_func)lua_pushtimet,
+        .decoder = lua_totimet},
+       {}};
+
+/* Type codecs */
+
+struct hash *codec_hash;
+char scriptdir[MAXPATHLEN];
+
+static unsigned int codec_hash_key(const void *data)
+{
+       const struct frrscript_codec *c = data;
+
+       return string_hash_make(c->typename);
+}
+
+static bool codec_hash_cmp(const void *d1, const void *d2)
+{
+       const struct frrscript_codec *e1 = d1;
+       const struct frrscript_codec *e2 = d2;
+
+       return strmatch(e1->typename, e2->typename);
+}
+
+static void *codec_alloc(void *arg)
+{
+       struct frrscript_codec *tmp = arg;
+
+       struct frrscript_codec *e =
+               XCALLOC(MTYPE_SCRIPT, sizeof(struct frrscript_codec));
+       e->typename = XSTRDUP(MTYPE_SCRIPT, tmp->typename);
+       e->encoder = tmp->encoder;
+       e->decoder = tmp->decoder;
+
+       return e;
+}
+
+#if 0
+static void codec_free(struct codec *c)
+{
+       XFREE(MTYPE_TMP, c->typename);
+       XFREE(MTYPE_TMP, c);
+}
+#endif
+
+/* Generic script APIs */
+
+int frrscript_call(struct frrscript *fs, struct frrscript_env *env)
+{
+       struct frrscript_codec c = {};
+       const void *arg;
+       const char *bindname;
+
+       /* Encode script arguments */
+       for (int i = 0; env && env[i].val != NULL; i++) {
+               bindname = env[i].name;
+               c.typename = env[i].typename;
+               arg = env[i].val;
+
+               struct frrscript_codec *codec = hash_lookup(codec_hash, &c);
+               assert(codec && "No encoder for type");
+               codec->encoder(fs->L, arg);
+
+               lua_setglobal(fs->L, bindname);
+       }
+
+       int ret = lua_pcall(fs->L, 0, 0, 0);
+
+       switch (ret) {
+       case LUA_OK:
+               break;
+       case LUA_ERRRUN:
+               zlog_err("Script '%s' runtime error: %s", fs->name,
+                        lua_tostring(fs->L, -1));
+               break;
+       case LUA_ERRMEM:
+               zlog_err("Script '%s' memory error: %s", fs->name,
+                        lua_tostring(fs->L, -1));
+               break;
+       case LUA_ERRERR:
+               zlog_err("Script '%s' error handler error: %s", fs->name,
+                        lua_tostring(fs->L, -1));
+               break;
+       case LUA_ERRGCMM:
+               zlog_err("Script '%s' garbage collector error: %s", fs->name,
+                        lua_tostring(fs->L, -1));
+               break;
+       default:
+               zlog_err("Script '%s' unknown error: %s", fs->name,
+                        lua_tostring(fs->L, -1));
+               break;
+       }
+
+       if (ret != LUA_OK) {
+               lua_pop(fs->L, 1);
+               goto done;
+       }
+
+done:
+       /* LUA_OK is 0, so we can just return lua_pcall's result directly */
+       return ret;
+}
+
+void *frrscript_get_result(struct frrscript *fs,
+                          const struct frrscript_env *result)
+{
+       void *r;
+       struct frrscript_codec c = {.typename = result->typename};
+
+       struct frrscript_codec *codec = hash_lookup(codec_hash, &c);
+       assert(codec && "No encoder for type");
+
+       if (!codec->decoder) {
+               zlog_err("No script decoder for type '%s'", result->typename);
+               return NULL;
+       }
+
+       lua_getglobal(fs->L, result->name);
+       r = codec->decoder(fs->L, -1);
+       lua_pop(fs->L, 1);
+
+       return r;
+}
+
+void frrscript_register_type_codec(struct frrscript_codec *codec)
+{
+       struct frrscript_codec c = *codec;
+
+       if (hash_lookup(codec_hash, &c)) {
+               zlog_backtrace(LOG_ERR);
+               assert(!"Type codec double-registered.");
+       }
+
+       assert(hash_get(codec_hash, &c, codec_alloc));
+}
+
+void frrscript_register_type_codecs(struct frrscript_codec *codecs)
+{
+       for (int i = 0; codecs[i].typename != NULL; i++)
+               frrscript_register_type_codec(&codecs[i]);
+}
+
+struct frrscript *frrscript_load(const char *name,
+                                int (*load_cb)(struct frrscript *))
+{
+       struct frrscript *fs = XCALLOC(MTYPE_SCRIPT, sizeof(struct frrscript));
+
+       fs->name = XSTRDUP(MTYPE_SCRIPT, name);
+       fs->L = luaL_newstate();
+       frrlua_export_logging(fs->L);
+
+       char fname[MAXPATHLEN];
+       snprintf(fname, sizeof(fname), "%s/%s.lua", scriptdir, fs->name);
+
+       int ret = luaL_loadfile(fs->L, fname);
+
+       switch (ret) {
+       case LUA_OK:
+               break;
+       case LUA_ERRSYNTAX:
+               zlog_err("Failed loading script '%s': syntax error: %s", fname,
+                        lua_tostring(fs->L, -1));
+               break;
+       case LUA_ERRMEM:
+               zlog_err("Failed loading script '%s': out-of-memory error: %s",
+                        fname, lua_tostring(fs->L, -1));
+               break;
+       case LUA_ERRGCMM:
+               zlog_err(
+                       "Failed loading script '%s': garbage collector error: %s",
+                       fname, lua_tostring(fs->L, -1));
+               break;
+       case LUA_ERRFILE:
+               zlog_err("Failed loading script '%s': file read error: %s",
+                        fname, lua_tostring(fs->L, -1));
+               break;
+       default:
+               zlog_err("Failed loading script '%s': unknown error: %s", fname,
+                        lua_tostring(fs->L, -1));
+               break;
+       }
+
+       if (ret != LUA_OK)
+               goto fail;
+
+       if (load_cb && (*load_cb)(fs) != 0)
+               goto fail;
+
+       return fs;
+fail:
+       frrscript_unload(fs);
+       return NULL;
+}
+
+void frrscript_unload(struct frrscript *fs)
+{
+       lua_close(fs->L);
+       XFREE(MTYPE_SCRIPT, fs->name);
+       XFREE(MTYPE_SCRIPT, fs);
+}
+
+void frrscript_init(const char *sd)
+{
+       codec_hash = hash_create(codec_hash_key, codec_hash_cmp,
+                                "Lua type encoders");
+
+       strlcpy(scriptdir, sd, sizeof(scriptdir));
+
+       /* Register core library types */
+       frrscript_register_type_codecs(frrscript_codecs_lib);
+}
+
+#endif /* HAVE_SCRIPTING */
diff --git a/lib/frrscript.h b/lib/frrscript.h
new file mode 100644 (file)
index 0000000..f4057f5
--- /dev/null
@@ -0,0 +1,138 @@
+/* Scripting foo
+ * Copyright (C) 2020  NVIDIA Corporation
+ * Quentin Young
+ *
+ * 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 __FRRSCRIPT_H__
+#define __FRRSCRIPT_H__
+
+#include <zebra.h>
+
+#ifdef HAVE_SCRIPTING
+
+#include <lua.h>
+#include "frrlua.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*encoder_func)(lua_State *, const void *);
+typedef void *(*decoder_func)(lua_State *, int);
+
+struct frrscript_codec {
+       const char *typename;
+       encoder_func encoder;
+       decoder_func decoder;
+};
+
+struct frrscript {
+       /* Script name */
+       char *name;
+
+       /* Lua state */
+       struct lua_State *L;
+};
+
+struct frrscript_env {
+       /* Value type */
+       const char *typename;
+
+       /* Binding name */
+       const char *name;
+
+       /* Value */
+       const void *val;
+};
+
+/*
+ * Create new FRR script.
+ */
+struct frrscript *frrscript_load(const char *name,
+                                int (*load_cb)(struct frrscript *));
+
+/*
+ * Destroy FRR script.
+ */
+void frrscript_unload(struct frrscript *fs);
+
+/*
+ * Register a Lua codec for a type.
+ *
+ * tname
+ *    Name of type; e.g., "peer", "ospf_interface", etc. Chosen at will.
+ *
+ * codec(s)
+ *    Function pointer to codec struct. Encoder function should push a Lua
+ *    table representing the passed argument - which will have the C type
+ *    associated with the chosen 'tname' to the provided stack. The decoder
+ *    function should pop a value from the top of the stack and return a heap
+ *    chunk containing that value. Allocations should be made with MTYPE_TMP.
+ *
+ *    If using the plural function variant, pass a NULL-terminated array.
+ *
+ */
+void frrscript_register_type_codec(struct frrscript_codec *codec);
+void frrscript_register_type_codecs(struct frrscript_codec *codecs);
+
+/*
+ * Initialize scripting subsystem. Call this before anything else.
+ *
+ * scriptdir
+ *    Directory in which to look for scripts
+ */
+void frrscript_init(const char *scriptdir);
+
+
+/*
+ * Call script.
+ *
+ * fs
+ *    The script to call; this is obtained from frrscript_load().
+ *
+ * env
+ *    The script's environment. Specify this as an array of frrscript_env.
+ *
+ * Returns:
+ *    0 if the script ran successfully, nonzero otherwise.
+ */
+int frrscript_call(struct frrscript *fs, struct frrscript_env *env);
+
+
+/*
+ * Get result from finished script.
+ *
+ * fs
+ *    The script. This script must have been run already.
+ *
+ * result
+ *    The result to extract from the script.
+ *    This reuses the frrscript_env type, but only the typename and name fields
+ *    need to be set. The value is returned directly.
+ *
+ * Returns:
+ *    The script result of the specified name and type, or NULL.
+ */
+void *frrscript_get_result(struct frrscript *fs,
+                          const struct frrscript_env *result);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* HAVE_SCRIPTING */
+
+#endif /* __FRRSCRIPT_H__ */
index 00953ff3b326c15158be06168316f45d00c93dd5..23e93b6d7d6eb89c65a26b26c20852a6cdf6fdc0 100644 (file)
@@ -103,7 +103,7 @@ struct hash {
  *
  * hash_cmp
  *    comparison function used for resolving collisions; when called with two
- *    data items, should return nonzero if the two items are equal and 0
+ *    data items, should return true if the two items are equal and false
  *    otherwise
  *
  * name
@@ -137,7 +137,7 @@ extern struct hash *hash_create(unsigned int (*hash_key)(const void *),
  *
  * hash_cmp
  *    comparison function used for resolving collisions; when called with two
- *    data items, should return nonzero if the two items are equal and 0
+ *    data items, should return true if the two items are equal and false
  *    otherwise
  *
  * name
index daede566f0a2cf89394e9b669535fc76a39949a7..0429e17d5c49307c5db3850054bf0559dddada72 100644 (file)
@@ -39,14 +39,10 @@ extern "C" {
 
 #define LDP_IGP_SYNC_HOLDDOWN_DEFAULT 0
 
-#define LDP_IGP_SYNC_HELLO_TIMEOUT 1
-
 /* LDP-IGP Sync structures */
 struct ldp_sync_info_cmd {
        uint16_t flags;
        uint16_t holddown;       /* timer value */
-       uint32_t sequence;       /* hello sequence number */
-       struct thread *t_hello;  /* hello timer for detecting LDP going down */
 };
 
 struct ldp_sync_info {
@@ -79,11 +75,6 @@ struct ldp_igp_sync_if_state_req {
        char name[INTERFACE_NAMSIZ];
 };
 
-struct ldp_igp_sync_hello {
-       int proto;
-       unsigned int sequence;
-};
-
 #ifdef __cplusplus
 }
 #endif
index 9c927ca4af99cae02c2091771516731656df9a58..cd8b5c98095369fef4839c30c42e0f343a35c1f5 100644 (file)
@@ -212,6 +212,57 @@ DEFUN (frr_version,
        return CMD_SUCCESS;
 }
 
+static struct call_back {
+       time_t readin_time;
+
+       void (*start_config)(void);
+       void (*end_config)(void);
+} callback;
+
+
+DEFUN_HIDDEN (start_config,
+             start_config_cmd,
+             "XFRR_start_configuration",
+             "The Beginning of Configuration\n")
+{
+       callback.readin_time = monotime(NULL);
+
+       if (callback.start_config)
+               (*callback.start_config)();
+
+       return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN (end_config,
+             end_config_cmd,
+             "XFRR_end_configuration",
+             "The End of Configuration\n")
+{
+       time_t readin_time;
+       char readin_time_str[MONOTIME_STRLEN];
+
+       readin_time = monotime(NULL);
+       readin_time -= callback.readin_time;
+
+       frrtime_to_interval(readin_time, readin_time_str,
+                           sizeof(readin_time_str));
+
+       zlog_info("Configuration Read in Took: %s", readin_time_str);
+
+       if (callback.end_config)
+               (*callback.end_config)();
+
+       return CMD_SUCCESS;
+}
+
+void cmd_init_config_callbacks(void (*start_config_cb)(void),
+                              void (*end_config_cb)(void))
+{
+       callback.start_config = start_config_cb;
+       callback.end_config = end_config_cb;
+}
+
+
 static void defaults_autocomplete(vector comps, struct cmd_token *token)
 {
        const char **p;
@@ -234,6 +285,9 @@ void lib_cmd_init(void)
 
        install_element(VIEW_NODE, &show_memory_cmd);
        install_element(VIEW_NODE, &show_modules_cmd);
+
+       install_element(CONFIG_NODE, &start_config_cmd);
+       install_element(CONFIG_NODE, &end_config_cmd);
 }
 
 /* Stats querying from users */
index 800596c5639b9e8d1be1e6b41ce110c0890d1d6a..b83883779cd05b050162800fa37ca587bb1cb5d3 100644 (file)
@@ -43,6 +43,7 @@
 #include "frrcu.h"
 #include "frr_pthread.h"
 #include "defaults.h"
+#include "frrscript.h"
 
 DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
 DEFINE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm))
@@ -55,6 +56,7 @@ char frr_vtydir[256];
 const char frr_dbdir[] = DAEMON_DB_DIR;
 #endif
 const char frr_moduledir[] = MODULE_PATH;
+const char frr_scriptdir[] = SCRIPT_PATH;
 
 char frr_protoname[256] = "NONE";
 char frr_protonameinst[256] = "NONE";
@@ -99,6 +101,8 @@ static void opt_extend(const struct optspec *os)
 #define OPTION_TCLI      1005
 #define OPTION_DB_FILE   1006
 #define OPTION_LOGGING   1007
+#define OPTION_LIMIT_FDS 1008
+#define OPTION_SCRIPTDIR 1009
 
 static const struct option lo_always[] = {
        {"help", no_argument, NULL, 'h'},
@@ -109,10 +113,12 @@ static const struct option lo_always[] = {
        {"pathspace", required_argument, NULL, 'N'},
        {"vty_socket", required_argument, NULL, OPTION_VTYSOCK},
        {"moduledir", required_argument, NULL, OPTION_MODULEDIR},
+       {"scriptdir", required_argument, NULL, OPTION_SCRIPTDIR},
        {"log", required_argument, NULL, OPTION_LOG},
        {"log-level", required_argument, NULL, OPTION_LOGLEVEL},
        {"tcli", no_argument, NULL, OPTION_TCLI},
        {"command-log-always", no_argument, NULL, OPTION_LOGGING},
+       {"limit-fds", required_argument, NULL, OPTION_LIMIT_FDS},
        {NULL}};
 static const struct optspec os_always = {
        "hvdM:F:N:",
@@ -124,9 +130,11 @@ static const struct optspec os_always = {
        "  -N, --pathspace    Insert prefix into config & socket paths\n"
        "      --vty_socket   Override vty socket path\n"
        "      --moduledir    Override modules directory\n"
+       "      --scriptdir    Override scripts directory\n"
        "      --log          Set Logging to stdout, syslog, or file:<name>\n"
        "      --log-level    Set Logging Level to use, debug, info, warn, etc\n"
-       "      --tcli         Use transaction-based CLI\n",
+       "      --tcli         Use transaction-based CLI\n"
+       "      --limit-fds    Limit number of fds supported\n",
        lo_always};
 
 
@@ -530,6 +538,14 @@ static int frr_opt(int opt)
                }
                di->module_path = optarg;
                break;
+       case OPTION_SCRIPTDIR:
+               if (di->script_path) {
+                       fprintf(stderr, "--scriptdir option specified more than once!\n");
+                       errors++;
+                       break;
+               }
+               di->script_path = optarg;
+               break;
        case OPTION_TCLI:
                di->cli_mode = FRR_CLI_TRANSACTIONAL;
                break;
@@ -552,6 +568,9 @@ static int frr_opt(int opt)
        case OPTION_LOGGING:
                di->log_always = true;
                break;
+       case OPTION_LIMIT_FDS:
+               di->limit_fds = strtoul(optarg, &err, 0);
+               break;
        default:
                return 1;
        }
@@ -711,6 +730,9 @@ struct thread_master *frr_init(void)
        lib_cmd_init();
 
        frr_pthread_init();
+#ifdef HAVE_SCRIPTING
+       frrscript_init(di->script_path ? di->script_path : frr_scriptdir);
+#endif
 
        log_ref_init();
        log_ref_vty_init();
@@ -739,6 +761,11 @@ enum frr_cli_mode frr_get_cli_mode(void)
        return di ? di->cli_mode : FRR_CLI_CLASSIC;
 }
 
+uint32_t frr_get_fd_limit(void)
+{
+       return di ? di->limit_fds : 0;
+}
+
 static int rcvd_signal = 0;
 
 static void rcv_signal(int signum)
index ab72299206c959220702ff979708e712ad8e684a..c4469314689da31e78bbd175a0b12575a4b960b8 100644 (file)
@@ -81,6 +81,7 @@ struct frr_daemon_info {
 #endif
        const char *vty_path;
        const char *module_path;
+       const char *script_path;
 
        const char *pathspace;
        bool zpathspace;
@@ -102,6 +103,9 @@ struct frr_daemon_info {
        size_t n_yang_modules;
 
        bool log_always;
+
+       /* Optional upper limit on the number of fds used in select/poll */
+       uint32_t limit_fds;
 };
 
 /* execname is the daemon's executable (and pidfile and configfile) name,
@@ -134,6 +138,7 @@ extern __attribute__((__noreturn__)) void frr_help_exit(int status);
 extern struct thread_master *frr_init(void);
 extern const char *frr_get_progname(void);
 extern enum frr_cli_mode frr_get_cli_mode(void);
+uint32_t frr_get_fd_limit(void);
 
 DECLARE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
 DECLARE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm))
@@ -158,6 +163,7 @@ extern char frr_zclientpath[256];
 extern const char frr_sysconfdir[];
 extern char frr_vtydir[256];
 extern const char frr_moduledir[];
+extern const char frr_scriptdir[];
 
 extern char frr_protoname[];
 extern char frr_protonameinst[];
diff --git a/lib/link_state.c b/lib/link_state.c
new file mode 100644 (file)
index 0000000..f8fdda6
--- /dev/null
@@ -0,0 +1,1284 @@
+/*
+ * Link State Database - link_state.c
+ *
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ *
+ * Copyright (C) 2020 Orange http://www.orange.com
+ *
+ * This file is part of Free Range Routing (FRR).
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "if.h"
+#include "linklist.h"
+#include "log.h"
+#include "command.h"
+#include "termtable.h"
+#include "memory.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "zclient.h"
+#include "stream.h"
+#include "link_state.h"
+
+/* Link State Memory allocation */
+DEFINE_MTYPE_STATIC(LIB, LS_DB, "Link State Database")
+
+/**
+ *  Link State Node management functions
+ */
+struct ls_node *ls_node_new(struct ls_node_id adv, struct in_addr rid,
+                           struct in6_addr rid6)
+{
+       struct ls_node *new;
+
+       if (adv.origin == NONE)
+               return NULL;
+
+       new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_node));
+       new->adv = adv;
+       if (!IPV4_NET0(rid.s_addr)) {
+               new->router_id = rid;
+               SET_FLAG(new->flags, LS_NODE_ROUTER_ID);
+       } else {
+               if (adv.origin == OSPFv2 || adv.origin == STATIC
+                   || adv.origin == DIRECT) {
+                       new->router_id = adv.id.ip.addr;
+                       SET_FLAG(new->flags, LS_NODE_ROUTER_ID);
+               }
+       }
+       if (!IN6_IS_ADDR_UNSPECIFIED(&rid6)) {
+               new->router6_id = rid6;
+               SET_FLAG(new->flags, LS_NODE_ROUTER_ID6);
+       }
+       return new;
+}
+
+void ls_node_del(struct ls_node *node)
+{
+       XFREE(MTYPE_LS_DB, node);
+       node = NULL;
+}
+
+int ls_node_same(struct ls_node *n1, struct ls_node *n2)
+{
+       if ((n1 && !n2) || (!n1 && n2))
+               return 0;
+
+       if (n1 == n2)
+               return 1;
+
+       if (n1->flags != n2->flags)
+               return 0;
+
+       if (n1->adv.origin != n2->adv.origin)
+               return 0;
+
+       if (!memcmp(&n1->adv.id, &n2->adv.id, sizeof(struct ls_node_id)))
+               return 0;
+
+       /* Do we need to test individually each field, instead performing a
+        * global memcmp? There is a risk that an old value that is bit masked
+        * i.e. corresponding flag = 0, will result into a false negative
+        */
+       if (!memcmp(n1, n2, sizeof(struct ls_node)))
+               return 0;
+       else
+               return 1;
+}
+
+/**
+ *  Link State Attributes management functions
+ */
+struct ls_attributes *ls_attributes_new(struct ls_node_id adv,
+                                       struct in_addr local,
+                                       struct in6_addr local6,
+                                       uint32_t local_id)
+{
+       struct ls_attributes *new;
+
+       if (adv.origin == NONE)
+               return NULL;
+
+       new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes));
+       new->adv = adv;
+       if (!IPV4_NET0(local.s_addr)) {
+               new->standard.local = local;
+               SET_FLAG(new->flags, LS_ATTR_LOCAL_ADDR);
+       }
+       if (!IN6_IS_ADDR_UNSPECIFIED(&local6)) {
+               new->standard.local6 = local6;
+               SET_FLAG(new->flags, LS_ATTR_LOCAL_ADDR6);
+       }
+       if (local_id != 0) {
+               new->standard.local_id = local_id;
+               SET_FLAG(new->flags, LS_ATTR_LOCAL_ID);
+       }
+
+       /* Check that almost one identifier is set */
+       if (!CHECK_FLAG(new->flags, LS_ATTR_LOCAL_ADDR | LS_ATTR_LOCAL_ADDR6
+           | LS_ATTR_LOCAL_ID)) {
+               XFREE(MTYPE_LS_DB, new);
+               return NULL;
+       }
+
+       return new;
+}
+
+void ls_attributes_del(struct ls_attributes *attr)
+{
+       if (!attr)
+               return;
+
+       if (attr->srlgs)
+               XFREE(MTYPE_LS_DB, attr->srlgs);
+
+       XFREE(MTYPE_LS_DB, attr);
+       attr = NULL;
+}
+
+int ls_attributes_same(struct ls_attributes *l1, struct ls_attributes *l2)
+{
+       if ((l1 && !l2) || (!l1 && l2))
+               return 0;
+
+       if (l1 == l2)
+               return 1;
+
+       if (l1->flags != l2->flags)
+               return 0;
+
+       if (l1->adv.origin != l2->adv.origin)
+               return 0;
+
+       if (!memcmp(&l1->adv.id, &l2->adv.id, sizeof(struct ls_node_id)))
+               return 0;
+
+       /* Do we need to test individually each field, instead performing a
+        * global memcmp? There is a risk that an old value that is bit masked
+        * i.e. corresponding flag = 0, will result into a false negative
+        */
+       if (!memcmp(l1, l2, sizeof(struct ls_attributes)))
+               return 0;
+       else
+               return 1;
+}
+
+/**
+ *  Link State Vertices management functions
+ */
+struct ls_vertex *ls_vertex_new(struct ls_node *node)
+{
+       struct ls_vertex *new;
+
+       if (node == NULL)
+               return NULL;
+
+       new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_vertex));
+       new->node = node;
+       new->incoming_edges = list_new();
+       new->outgoing_edges = list_new();
+       new->prefixes = list_new();
+
+       return new;
+}
+
+void ls_vertex_del(struct ls_vertex *vertex)
+{
+       if (vertex == NULL)
+               return;
+
+       list_delete_all_node(vertex->incoming_edges);
+       list_delete_all_node(vertex->outgoing_edges);
+       list_delete_all_node(vertex->prefixes);
+       XFREE(MTYPE_LS_DB, vertex);
+       vertex = NULL;
+}
+
+struct ls_vertex *ls_vertex_add(struct ls_ted *ted, struct ls_node *node)
+{
+       struct ls_vertex *new;
+
+       if ((ted == NULL) || (node == NULL))
+               return NULL;
+
+       new = ls_vertex_new(node);
+       if (!new)
+               return NULL;
+
+       /* set Key as the IPv4/Ipv6 Router ID or ISO System ID */
+       switch (node->adv.origin) {
+       case OSPFv2:
+       case STATIC:
+       case DIRECT:
+               memcpy(&new->key, &node->adv.id.ip.addr, IPV4_MAX_BYTELEN);
+               break;
+       case ISIS_L1:
+       case ISIS_L2:
+               memcpy(&new->key, &node->adv.id.iso.sys_id, ISO_SYS_ID_LEN);
+               break;
+       default:
+               new->key = 0;
+               break;
+       }
+
+       /* Remove Vertex if key is not set */
+       if (new->key == 0) {
+               ls_vertex_del(new);
+               return NULL;
+       }
+
+       /* Add Vertex to TED */
+       vertices_add(&ted->vertices, new);
+
+       return new;
+}
+
+struct ls_vertex *ls_vertex_update(struct ls_ted *ted, struct ls_node *node)
+{
+       struct ls_vertex *old;
+
+       if (node == NULL)
+               return NULL;
+
+       old = ls_find_vertex_by_id(ted, node->adv);
+       if (old) {
+               if (!ls_node_same(old->node, node)) {
+                       ls_node_del(old->node);
+                       old->node = node;
+               }
+               return old;
+       }
+
+       return ls_vertex_add(ted, node);
+}
+
+void ls_vertex_remove(struct ls_ted *ted, struct ls_vertex *vertex)
+{
+       vertices_del(&ted->vertices, vertex);
+       ls_vertex_del(vertex);
+}
+
+struct ls_vertex *ls_find_vertex_by_key(struct ls_ted *ted, const uint64_t key)
+{
+       struct ls_vertex node = {};
+
+       if (key == 0)
+               return NULL;
+
+       node.key = key;
+       return vertices_find(&ted->vertices, &node);
+}
+
+struct ls_vertex *ls_find_vertex_by_id(struct ls_ted *ted,
+                                      struct ls_node_id nid)
+{
+       struct ls_vertex node = {};
+
+       switch (nid.origin) {
+       case OSPFv2:
+       case STATIC:
+       case DIRECT:
+               memcpy(&node.key, &nid.id.ip.addr, IPV4_MAX_BYTELEN);
+               break;
+       case ISIS_L1:
+       case ISIS_L2:
+               memcpy(&node.key, &nid.id.iso.sys_id, ISO_SYS_ID_LEN);
+               break;
+       default:
+               return NULL;
+       }
+
+       return vertices_find(&ted->vertices, &node);
+}
+
+int ls_vertex_same(struct ls_vertex *v1, struct ls_vertex *v2)
+{
+       if ((v1 && !v2) || (!v1 && v2))
+               return 0;
+
+       if (!v1 && !v2)
+               return 1;
+
+       if (v1->key != v2->key)
+               return 0;
+
+       if (v1->node == v2->node)
+               return 1;
+
+       return ls_node_same(v1->node, v2->node);
+}
+
+/**
+ * Link State Edges management functions
+ */
+
+/**
+ * This function allows to connect the Edge to the vertices present in the TED.
+ * A temporary vertex that corresponds to the source of this Edge i.e. the
+ * advertised router, is created if not found in the Data Base. If a Edge that
+ * corresponds to the reverse path is found, the Edge is attached to the
+ * destination vertex as destination and reverse Edge is attached to the source
+ * vertex as source.
+ *
+ * @param ted  Link State Data Base
+ * @param edge Link State Edge to be attached
+ */
+static void ls_edge_connect_to(struct ls_ted *ted, struct ls_edge *edge)
+{
+       struct ls_vertex *vertex = NULL;
+       struct ls_node *node;
+       struct ls_edge *dst;
+       const struct in_addr inaddr_any = {.s_addr = INADDR_ANY};
+
+       /* First, search if there is a Vertex that correspond to the Node ID */
+       vertex = ls_find_vertex_by_id(ted, edge->attributes->adv);
+       if (vertex == NULL) {
+               /* Create a new temporary Node & Vertex if not found */
+               node = ls_node_new(edge->attributes->adv, inaddr_any,
+                                  in6addr_any);
+               vertex = ls_vertex_add(ted, node);
+       }
+       /* and attach the edge as source to the vertex */
+       listnode_add(vertex->outgoing_edges, edge);
+       edge->source = vertex;
+
+       /* Then search if there is a reverse Edge */
+       dst = ls_find_edge_by_destination(ted, edge->attributes);
+       /* attach the destination edge to the vertex */
+       if (dst) {
+               listnode_add(vertex->incoming_edges, dst);
+               dst->destination = vertex;
+               /* and destination vertex to this edge */
+               vertex = dst->source;
+               listnode_add(vertex->incoming_edges, edge);
+               edge->destination = vertex;
+       }
+}
+
+struct ls_edge *ls_edge_add(struct ls_ted *ted,
+                           struct ls_attributes *attributes)
+{
+       struct ls_edge *new;
+
+       if (attributes == NULL)
+               return NULL;
+
+       new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_edge));
+       new->attributes = attributes;
+       /* Key is the IPv4 local address */
+       if (!IPV4_NET0(attributes->standard.local.s_addr))
+               new->key = ((uint64_t)attributes->standard.local.s_addr)
+                          & 0xffffffff;
+       /* or the IPv6 local address if IPv4 is not defined */
+       else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.local6))
+               new->key = (uint64_t)(attributes->standard.local6.s6_addr32[0]
+                                     & 0xffffffff)
+                          | ((uint64_t)attributes->standard.local6.s6_addr32[1]
+                             << 32);
+       /* of local identifier if no IP addresses are defined */
+       else if (attributes->standard.local_id != 0)
+               new->key = (uint64_t)(
+                       (attributes->standard.local_id & 0xffffffff)
+                       | ((uint64_t)attributes->standard.remote_id << 32));
+
+       /* Remove Edge if key is not known */
+       if (new->key == 0) {
+               XFREE(MTYPE_LS_DB, new);
+               return NULL;
+       }
+
+       edges_add(&ted->edges, new);
+
+       /* Finally, connect edge to vertices */
+       ls_edge_connect_to(ted, new);
+
+       return new;
+}
+
+struct ls_edge *ls_find_edge_by_key(struct ls_ted *ted, const uint64_t key)
+{
+       struct ls_edge edge = {};
+
+       if (key == 0)
+               return NULL;
+
+       edge.key = key;
+       return edges_find(&ted->edges, &edge);
+}
+
+struct ls_edge *ls_find_edge_by_source(struct ls_ted *ted,
+                                      struct ls_attributes *attributes)
+{
+       struct ls_edge edge = {};
+
+       if (attributes == NULL)
+               return NULL;
+
+       /* Key is the IPv4 local address */
+       if (!IPV4_NET0(attributes->standard.local.s_addr))
+               edge.key = ((uint64_t)attributes->standard.local.s_addr)
+                          & 0xffffffff;
+       /* or the IPv6 local address if IPv4 is not defined */
+       else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.local6))
+               edge.key = (uint64_t)(attributes->standard.local6.s6_addr32[0]
+                                     & 0xffffffff)
+                          | ((uint64_t)attributes->standard.local6.s6_addr32[1]
+                             << 32);
+       /* of local identifier if no IP addresses are defined */
+       else if (attributes->standard.local_id != 0)
+               edge.key = (uint64_t)(
+                       (attributes->standard.local_id & 0xffffffff)
+                       | ((uint64_t)attributes->standard.remote_id << 32));
+
+       if (edge.key == 0)
+               return NULL;
+
+       return edges_find(&ted->edges, &edge);
+}
+
+struct ls_edge *ls_find_edge_by_destination(struct ls_ted *ted,
+                                           struct ls_attributes *attributes)
+{
+       struct ls_edge edge = {};
+
+       if (attributes == NULL)
+               return NULL;
+
+       /* Key is the IPv4 local address */
+       if (!IPV4_NET0(attributes->standard.remote.s_addr))
+               edge.key = ((uint64_t)attributes->standard.remote.s_addr)
+                          & 0xffffffff;
+       /* or the IPv6 local address if IPv4 is not defined */
+       else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.remote6))
+               edge.key =
+                       (uint64_t)(attributes->standard.remote6.s6_addr32[0]
+                                  & 0xffffffff)
+                       | ((uint64_t)attributes->standard.remote6.s6_addr32[1]
+                          << 32);
+       /* of local identifier if no IP addresses are defined */
+       else if (attributes->standard.remote_id != 0)
+               edge.key = (uint64_t)(
+                       (attributes->standard.remote_id & 0xffffffff)
+                       | ((uint64_t)attributes->standard.local_id << 32));
+
+       if (edge.key == 0)
+               return NULL;
+
+       return edges_find(&ted->edges, &edge);
+}
+
+struct ls_edge *ls_edge_update(struct ls_ted *ted,
+                              struct ls_attributes *attributes)
+{
+       struct ls_edge *old;
+
+       if (attributes == NULL)
+               return NULL;
+
+       /* First, search for an existing Edge */
+       old = ls_find_edge_by_source(ted, attributes);
+       if (old) {
+               /* Check if attributes are similar */
+               if (!ls_attributes_same(old->attributes, attributes)) {
+                       ls_attributes_del(old->attributes);
+                       old->attributes = attributes;
+               }
+               return old;
+       }
+
+       /* If not found, add new Edge from the attributes */
+       return ls_edge_add(ted, attributes);
+}
+
+void ls_edge_del(struct ls_ted *ted, struct ls_edge *edge)
+{
+       /* Fist disconnect Edge */
+       ls_disconnect_edge(edge);
+       /* Then remove it from the Data Base */
+       edges_del(&ted->edges, edge);
+       XFREE(MTYPE_LS_DB, edge);
+}
+
+/**
+ * Link State Subnet Management functions.
+ */
+struct ls_subnet *ls_subnet_add(struct ls_ted *ted,
+                               struct ls_prefix *ls_pref)
+{
+       struct ls_subnet *new;
+       struct ls_vertex *vertex;
+       struct ls_node *node;
+       const struct in_addr inaddr_any = {.s_addr = INADDR_ANY};
+
+       if (ls_pref == NULL)
+               return NULL;
+
+       new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_subnet));
+       new->ls_pref = ls_pref;
+       new->key = ls_pref->pref;
+
+       /* Find Vertex */
+       vertex = ls_find_vertex_by_id(ted, ls_pref->adv);
+       if (vertex == NULL) {
+               /* Create a new temporary Node & Vertex if not found */
+               node = ls_node_new(ls_pref->adv, inaddr_any, in6addr_any);
+               vertex = ls_vertex_add(ted, node);
+       }
+       /* And attach the subnet to the corresponding Vertex */
+       new->vertex = vertex;
+       listnode_add(vertex->prefixes, new);
+
+       subnets_add(&ted->subnets, new);
+
+       return new;
+}
+
+void ls_subnet_del(struct ls_ted *ted, struct ls_subnet *subnet)
+{
+       subnets_del(&ted->subnets, subnet);
+       XFREE(MTYPE_LS_DB, subnet);
+}
+
+struct ls_subnet *ls_find_subnet(struct ls_ted *ted, const struct prefix prefix)
+{
+       struct ls_subnet subnet = {};
+
+       subnet.key = prefix;
+       return subnets_find(&ted->subnets, &subnet);
+}
+
+/**
+ * Link State TED management functions
+ */
+struct ls_ted *ls_ted_new(const uint32_t key, const char *name,
+                         uint32_t as_number)
+{
+       struct ls_ted *new;
+
+       new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_ted));
+       if (new == NULL)
+               return new;
+
+       /* Set basic information for this ted */
+       new->key = key;
+       new->as_number = as_number;
+       strlcpy(new->name, name, MAX_NAME_LENGTH);
+
+       /* Initialize the various RB tree */
+       vertices_init(&new->vertices);
+       edges_init(&new->edges);
+       subnets_init(&new->subnets);
+
+       return new;
+}
+
+void ls_ted_del(struct ls_ted *ted)
+{
+       if (ted == NULL)
+               return;
+
+       /* Release RB Tree */
+       vertices_fini(&ted->vertices);
+       edges_fini(&ted->edges);
+       subnets_fini(&ted->subnets);
+
+       XFREE(MTYPE_LS_DB, ted);
+       ted = NULL;
+}
+
+void ls_connect(struct ls_vertex *vertex, struct ls_edge *edge, bool source)
+{
+       if (vertex == NULL || edge == NULL)
+               return;
+
+       if (source) {
+               listnode_add(vertex->outgoing_edges, edge);
+               edge->source = vertex;
+       } else {
+               listnode_add(vertex->incoming_edges, edge);
+               edge->destination = vertex;
+       }
+}
+
+void ls_disconnect(struct ls_vertex *vertex, struct ls_edge *edge, bool source)
+{
+
+       if (vertex == NULL || edge == NULL)
+               return;
+
+       if (source) {
+               listnode_delete(vertex->outgoing_edges, edge);
+               edge->source = NULL;
+       } else {
+               listnode_delete(vertex->incoming_edges, edge);
+               edge->destination = NULL;
+       }
+}
+
+void ls_connect_vertices(struct ls_vertex *src, struct ls_vertex *dst,
+                        struct ls_edge *edge)
+{
+       if (edge == NULL)
+               return;
+
+       edge->source = src;
+       edge->destination = dst;
+
+       if (src != NULL)
+               listnode_add(src->outgoing_edges, edge);
+
+       if (dst != NULL)
+               listnode_add(dst->incoming_edges, edge);
+
+}
+
+void ls_disconnect_edge(struct ls_edge *edge)
+{
+       if (edge == NULL)
+               return;
+
+       ls_disconnect(edge->source, edge, true);
+       ls_disconnect(edge->destination, edge, false);
+}
+
+/**
+ * Link State Message management functions
+ */
+
+static struct ls_node *ls_parse_node(struct stream *s)
+{
+       struct ls_node *node;
+       size_t len;
+
+       node = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_node));
+       if (node == NULL)
+               return NULL;
+
+       STREAM_GET(&node->adv, s, sizeof(struct ls_node_id));
+       STREAM_GETW(s, node->flags);
+       if (CHECK_FLAG(node->flags, LS_NODE_NAME)) {
+               STREAM_GETC(s, len);
+               STREAM_GET(node->name, s, len);
+       }
+       if (CHECK_FLAG(node->flags, LS_NODE_ROUTER_ID))
+               node->router_id.s_addr = stream_get_ipv4(s);
+       if (CHECK_FLAG(node->flags, LS_NODE_ROUTER_ID6))
+               STREAM_GET(&node->router6_id, s, IPV6_MAX_BYTELEN);
+       if (CHECK_FLAG(node->flags, LS_NODE_FLAG))
+               STREAM_GETC(s, node->node_flag);
+       if (CHECK_FLAG(node->flags, LS_NODE_TYPE))
+               STREAM_GETC(s, node->type);
+       if (CHECK_FLAG(node->flags, LS_NODE_AS_NUMBER))
+               STREAM_GETL(s, node->as_number);
+       if (CHECK_FLAG(node->flags, LS_NODE_SR)) {
+               STREAM_GETL(s, node->srgb.lower_bound);
+               STREAM_GETL(s, node->srgb.range_size);
+               STREAM_GETC(s, node->srgb.flag);
+               STREAM_GET(node->algo, s, 2);
+       }
+       if (CHECK_FLAG(node->flags, LS_NODE_SRLB)) {
+               STREAM_GETL(s, node->srlb.lower_bound);
+               STREAM_GETL(s, node->srlb.range_size);
+       }
+       if (CHECK_FLAG(node->flags, LS_NODE_MSD))
+               STREAM_GETC(s, node->msd);
+
+       return node;
+
+stream_failure:
+       zlog_err("LS(%s): Could not parse Link State Node. Abort!", __func__);
+       XFREE(MTYPE_LS_DB, node);
+       return NULL;
+}
+
+static struct ls_attributes *ls_parse_attributes(struct stream *s)
+{
+       struct ls_attributes *attr;
+       size_t len;
+
+       attr = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes));
+       if (attr == NULL)
+               return NULL;
+       attr->srlgs = NULL;
+
+       STREAM_GET(&attr->adv, s, sizeof(struct ls_node_id));
+       STREAM_GETL(s, attr->flags);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_NAME)) {
+               STREAM_GETC(s, len);
+               STREAM_GET(attr->name, s, len);
+       }
+       if (CHECK_FLAG(attr->flags, LS_ATTR_METRIC))
+               STREAM_GETL(s, attr->standard.metric);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC))
+               STREAM_GETL(s, attr->standard.te_metric);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP))
+               STREAM_GETL(s, attr->standard.admin_group);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR))
+               attr->standard.local.s_addr = stream_get_ipv4(s);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR))
+               attr->standard.remote.s_addr = stream_get_ipv4(s);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6))
+               STREAM_GET(&attr->standard.local6, s, IPV6_MAX_BYTELEN);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6))
+               STREAM_GET(&attr->standard.remote6, s, IPV6_MAX_BYTELEN);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID))
+               STREAM_GETL(s, attr->standard.local_id);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ID))
+               STREAM_GETL(s, attr->standard.remote_id);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_BW))
+               STREAM_GETF(s, attr->standard.max_bw);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW))
+               STREAM_GETF(s, attr->standard.max_rsv_bw);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_UNRSV_BW))
+               for (len = 0; len < MAX_CLASS_TYPE; len++)
+                       STREAM_GETF(s, attr->standard.unrsv_bw[len]);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_AS))
+               STREAM_GETL(s, attr->standard.remote_as);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR))
+               attr->standard.remote_addr.s_addr = stream_get_ipv4(s);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR6))
+               STREAM_GET(&attr->standard.remote_addr6, s, IPV6_MAX_BYTELEN);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_DELAY))
+               STREAM_GETL(s, attr->extended.delay);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY)) {
+               STREAM_GETL(s, attr->extended.min_delay);
+               STREAM_GETL(s, attr->extended.max_delay);
+       }
+       if (CHECK_FLAG(attr->flags, LS_ATTR_JITTER))
+               STREAM_GETL(s, attr->extended.jitter);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_PACKET_LOSS))
+               STREAM_GETL(s, attr->extended.pkt_loss);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_AVA_BW))
+               STREAM_GETF(s, attr->extended.ava_bw);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_RSV_BW))
+               STREAM_GETF(s, attr->extended.rsv_bw);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_USE_BW))
+               STREAM_GETF(s, attr->extended.used_bw);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID)) {
+               STREAM_GETL(s, attr->adj_sid[0].sid);
+               STREAM_GETC(s, attr->adj_sid[0].flags);
+               STREAM_GETC(s, attr->adj_sid[0].weight);
+               if (attr->adv.origin == ISIS_L1 || attr->adv.origin == ISIS_L2)
+                       STREAM_GET(attr->adj_sid[0].neighbor.sysid, s,
+                                  ISO_SYS_ID_LEN);
+               else if (attr->adv.origin == OSPFv2)
+                       attr->adj_sid[0].neighbor.addr.s_addr =
+                               stream_get_ipv4(s);
+       }
+       if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID)) {
+               STREAM_GETL(s, attr->adj_sid[1].sid);
+               STREAM_GETC(s, attr->adj_sid[1].flags);
+               STREAM_GETC(s, attr->adj_sid[1].weight);
+               if (attr->adv.origin == ISIS_L1 || attr->adv.origin == ISIS_L2)
+                       STREAM_GET(attr->adj_sid[1].neighbor.sysid, s,
+                                  ISO_SYS_ID_LEN);
+               else if (attr->adv.origin == OSPFv2)
+                       attr->adj_sid[1].neighbor.addr.s_addr =
+                               stream_get_ipv4(s);
+       }
+       if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) {
+               STREAM_GETC(s, len);
+               attr->srlgs = XCALLOC(MTYPE_LS_DB, len*sizeof(uint32_t));
+               attr->srlg_len = len;
+               for (len = 0; len < attr->srlg_len; len++)
+                       STREAM_GETL(s, attr->srlgs[len]);
+       }
+
+       return attr;
+
+stream_failure:
+       zlog_err("LS(%s): Could not parse Link State Attributes. Abort!",
+                __func__);
+       /* Clean memeory allocation */
+       if (attr->srlgs != NULL)
+               XFREE(MTYPE_LS_DB, attr->srlgs);
+       XFREE(MTYPE_LS_DB, attr);
+       return NULL;
+
+}
+
+static struct ls_prefix *ls_parse_prefix(struct stream *s)
+{
+       struct ls_prefix *ls_pref;
+       size_t len;
+
+       ls_pref = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_prefix));
+       if (ls_pref == NULL)
+               return NULL;
+
+       STREAM_GET(&ls_pref->adv, s, sizeof(struct ls_node_id));
+       STREAM_GETW(s, ls_pref->flags);
+       STREAM_GETC(s, ls_pref->pref.family);
+       STREAM_GETW(s, ls_pref->pref.prefixlen);
+       len = prefix_blen(&ls_pref->pref);
+       STREAM_GET(&ls_pref->pref.u.prefix, s, len);
+       if (CHECK_FLAG(ls_pref->flags, LS_PREF_IGP_FLAG))
+               STREAM_GETC(s, ls_pref->igp_flag);
+       if (CHECK_FLAG(ls_pref->flags, LS_PREF_ROUTE_TAG))
+               STREAM_GETL(s, ls_pref->route_tag);
+       if (CHECK_FLAG(ls_pref->flags, LS_PREF_EXTENDED_TAG))
+               STREAM_GETQ(s, ls_pref->extended_tag);
+       if (CHECK_FLAG(ls_pref->flags, LS_PREF_METRIC))
+               STREAM_GETL(s, ls_pref->metric);
+       if (CHECK_FLAG(ls_pref->flags, LS_PREF_SR)) {
+               STREAM_GETL(s, ls_pref->sr.sid);
+               STREAM_GETC(s, ls_pref->sr.sid_flag);
+               STREAM_GETC(s, ls_pref->sr.algo);
+       }
+
+       return ls_pref;
+
+stream_failure:
+       zlog_err("LS(%s): Could not parse Link State Prefix. Abort!", __func__);
+       XFREE(MTYPE_LS_DB, ls_pref);
+       return NULL;
+}
+
+struct ls_message *ls_parse_msg(struct stream *s)
+{
+       struct ls_message *msg;
+
+       msg = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_message));
+       if (msg == NULL)
+               return NULL;
+
+       /* Read LS Message header */
+       STREAM_GETC(s, msg->event);
+       STREAM_GETC(s, msg->type);
+       STREAM_GET(&msg->remote_id, s, sizeof(struct ls_node_id));
+
+       /* Read Message Payload */
+       switch (msg->type) {
+       case LS_MSG_TYPE_NODE:
+               msg->data.node = ls_parse_node(s);
+               break;
+       case LS_MSG_TYPE_ATTRIBUTES:
+               msg->data.attr = ls_parse_attributes(s);
+               break;
+       case LS_MSG_TYPE_PREFIX:
+               msg->data.prefix = ls_parse_prefix(s);
+               break;
+       default:
+               zlog_err("Unsupported Payload");
+               goto stream_failure;
+       }
+
+       if (msg->data.node == NULL || msg->data.attr == NULL
+           || msg->data.prefix == NULL)
+               goto stream_failure;
+
+       return msg;
+
+stream_failure:
+       zlog_err("LS(%s): Could not parse LS message. Abort!", __func__);
+       XFREE(MTYPE_LS_DB, msg);
+       return NULL;
+}
+
+static int ls_format_node(struct stream *s, struct ls_node *node)
+{
+       size_t len;
+
+       /* Push Advertise node information first */
+       stream_put(s, &node->adv, sizeof(struct ls_node_id));
+
+       /* Push Flags & Origin then Node information if there are present */
+       stream_putw(s, node->flags);
+       if (CHECK_FLAG(node->flags, LS_NODE_NAME)) {
+               len = strlen(node->name);
+               stream_putc(s, len + 1);
+               stream_put(s, node->name, len);
+               stream_putc(s, '\0');
+       }
+       if (CHECK_FLAG(node->flags, LS_NODE_ROUTER_ID))
+               stream_put_ipv4(s, node->router_id.s_addr);
+       if (CHECK_FLAG(node->flags, LS_NODE_ROUTER_ID6))
+               stream_put(s, &node->router6_id, IPV6_MAX_BYTELEN);
+       if (CHECK_FLAG(node->flags, LS_NODE_FLAG))
+               stream_putc(s, node->node_flag);
+       if (CHECK_FLAG(node->flags, LS_NODE_TYPE))
+               stream_putc(s, node->type);
+       if (CHECK_FLAG(node->flags, LS_NODE_AS_NUMBER))
+               stream_putl(s, node->as_number);
+       if (CHECK_FLAG(node->flags, LS_NODE_SR)) {
+               stream_putl(s, node->srgb.lower_bound);
+               stream_putl(s, node->srgb.range_size);
+               stream_putc(s, node->srgb.flag);
+               stream_put(s, node->algo, 2);
+       }
+       if (CHECK_FLAG(node->flags, LS_NODE_SRLB)) {
+               stream_putl(s, node->srlb.lower_bound);
+               stream_putl(s, node->srlb.range_size);
+       }
+       if (CHECK_FLAG(node->flags, LS_NODE_MSD))
+               stream_putc(s, node->msd);
+
+       return 0;
+}
+
+static int ls_format_attributes(struct stream *s, struct ls_attributes *attr)
+{
+       size_t len;
+
+       /* Push Advertise node information first */
+       stream_put(s, &attr->adv, sizeof(struct ls_node_id));
+
+       /* Push Flags & Origin then LS attributes if there are present */
+       stream_putl(s, attr->flags);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_NAME)) {
+               len = strlen(attr->name);
+               stream_putc(s, len + 1);
+               stream_put(s, attr->name, len);
+               stream_putc(s, '\0');
+       }
+       if (CHECK_FLAG(attr->flags, LS_ATTR_METRIC))
+               stream_putl(s, attr->standard.metric);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC))
+               stream_putl(s, attr->standard.te_metric);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP))
+               stream_putl(s, attr->standard.admin_group);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR))
+               stream_put_ipv4(s, attr->standard.local.s_addr);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR))
+               stream_put_ipv4(s, attr->standard.remote.s_addr);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6))
+               stream_put(s, &attr->standard.local6, IPV6_MAX_BYTELEN);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6))
+               stream_put(s, &attr->standard.remote6, IPV6_MAX_BYTELEN);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID))
+               stream_putl(s, attr->standard.local_id);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ID))
+               stream_putl(s, attr->standard.remote_id);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_BW))
+               stream_putf(s, attr->standard.max_bw);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW))
+               stream_putf(s, attr->standard.max_rsv_bw);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_UNRSV_BW))
+               for (len = 0; len < MAX_CLASS_TYPE; len++)
+                       stream_putf(s, attr->standard.unrsv_bw[len]);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_AS))
+               stream_putl(s, attr->standard.remote_as);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR))
+               stream_put_ipv4(s, attr->standard.remote_addr.s_addr);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR6))
+               stream_put(s, &attr->standard.remote_addr6, IPV6_MAX_BYTELEN);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_DELAY))
+               stream_putl(s, attr->extended.delay);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY)) {
+               stream_putl(s, attr->extended.min_delay);
+               stream_putl(s, attr->extended.max_delay);
+       }
+       if (CHECK_FLAG(attr->flags, LS_ATTR_JITTER))
+               stream_putl(s, attr->extended.jitter);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_PACKET_LOSS))
+               stream_putl(s, attr->extended.pkt_loss);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_AVA_BW))
+               stream_putf(s, attr->extended.ava_bw);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_RSV_BW))
+               stream_putf(s, attr->extended.rsv_bw);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_USE_BW))
+               stream_putf(s, attr->extended.used_bw);
+       if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID)) {
+               stream_putl(s, attr->adj_sid[0].sid);
+               stream_putc(s, attr->adj_sid[0].flags);
+               stream_putc(s, attr->adj_sid[0].weight);
+               if (attr->adv.origin == ISIS_L1 || attr->adv.origin == ISIS_L2)
+                       stream_put(s, attr->adj_sid[0].neighbor.sysid,
+                                  ISO_SYS_ID_LEN);
+               else if (attr->adv.origin == OSPFv2)
+                       stream_put_ipv4(s,
+                                       attr->adj_sid[0].neighbor.addr.s_addr);
+       }
+       if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID)) {
+               stream_putl(s, attr->adj_sid[1].sid);
+               stream_putc(s, attr->adj_sid[1].flags);
+               stream_putc(s, attr->adj_sid[1].weight);
+               if (attr->adv.origin == ISIS_L1 || attr->adv.origin == ISIS_L2)
+                       stream_put(s, attr->adj_sid[1].neighbor.sysid,
+                                  ISO_SYS_ID_LEN);
+               else if (attr->adv.origin == OSPFv2)
+                       stream_put_ipv4(s,
+                                       attr->adj_sid[1].neighbor.addr.s_addr);
+       }
+       if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) {
+               stream_putc(s, attr->srlg_len);
+               for (len = 0; len < attr->srlg_len; len++)
+                       stream_putl(s, attr->srlgs[len]);
+       }
+
+       return 0;
+}
+
+static int ls_format_prefix(struct stream *s, struct ls_prefix *ls_pref)
+{
+       size_t len;
+
+       /* Push Advertise node information first */
+       stream_put(s, &ls_pref->adv, sizeof(struct ls_node_id));
+
+       /* Push Flags, Origin & Prefix then information if there are present */
+       stream_putw(s, ls_pref->flags);
+       stream_putc(s, ls_pref->pref.family);
+       stream_putw(s, ls_pref->pref.prefixlen);
+       len = prefix_blen(&ls_pref->pref);
+       stream_put(s, &ls_pref->pref.u.prefix, len);
+       if (CHECK_FLAG(ls_pref->flags, LS_PREF_IGP_FLAG))
+               stream_putc(s, ls_pref->igp_flag);
+       if (CHECK_FLAG(ls_pref->flags, LS_PREF_ROUTE_TAG))
+               stream_putl(s, ls_pref->route_tag);
+       if (CHECK_FLAG(ls_pref->flags, LS_PREF_EXTENDED_TAG))
+               stream_putq(s, ls_pref->extended_tag);
+       if (CHECK_FLAG(ls_pref->flags, LS_PREF_METRIC))
+               stream_putl(s, ls_pref->metric);
+       if (CHECK_FLAG(ls_pref->flags, LS_PREF_SR)) {
+               stream_putl(s, ls_pref->sr.sid);
+               stream_putc(s, ls_pref->sr.sid_flag);
+               stream_putc(s, ls_pref->sr.algo);
+       }
+
+       return 0;
+}
+
+static int ls_format_msg(struct stream *s, struct ls_message *msg)
+{
+
+       /* Prepare Link State header */
+       stream_putc(s, msg->event);
+       stream_putc(s, msg->type);
+       stream_put(s, &msg->remote_id, sizeof(struct ls_node_id));
+
+       /* Add Message Payload */
+       switch (msg->type) {
+       case LS_MSG_TYPE_NODE:
+               return ls_format_node(s, msg->data.node);
+       case LS_MSG_TYPE_ATTRIBUTES:
+               return ls_format_attributes(s, msg->data.attr);
+       case LS_MSG_TYPE_PREFIX:
+               return ls_format_prefix(s, msg->data.prefix);
+       default:
+               zlog_warn("Unsupported Payload");
+               break;
+       }
+
+       return -1;
+}
+
+int ls_send_msg(struct zclient *zclient, struct ls_message *msg,
+               struct zapi_opaque_reg_info *dst)
+{
+       struct stream *s;
+       uint16_t flags = 0;
+
+       /* Check buffer size */
+       if (STREAM_SIZE(zclient->obuf) <
+           (ZEBRA_HEADER_SIZE + sizeof(uint32_t) + sizeof(msg)))
+               return -1;
+
+       s = zclient->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, ZEBRA_OPAQUE_MESSAGE, VRF_DEFAULT);
+
+       /* Send sub-type, flags and destination for unicast message */
+       stream_putl(s, LINK_STATE_UPDATE);
+       if (dst != NULL) {
+               SET_FLAG(flags, ZAPI_OPAQUE_FLAG_UNICAST);
+               stream_putw(s, flags);
+               /* Send destination client info */
+               stream_putc(s, dst->proto);
+               stream_putw(s, dst->instance);
+               stream_putl(s, dst->session_id);
+       } else
+               stream_putw(s, flags);
+
+       /* Format Link State message */
+       if (ls_format_msg(s, msg) < 0) {
+               stream_reset(s);
+               return -1;
+       }
+
+       /* Put length into the header at the start of the stream. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zclient_send_message(zclient);
+}
+
+struct ls_message *ls_vertex2msg(struct ls_message *msg,
+                                struct ls_vertex *vertex)
+{
+       /* Allocate space if needed */
+       if (msg == NULL)
+               msg = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_message));
+       else
+               memset(msg, 0, sizeof(*msg));
+
+       msg->type = LS_MSG_TYPE_NODE;
+       msg->data.node = vertex->node;
+       msg->remote_id.origin = NONE;
+
+       return msg;
+}
+
+struct ls_message *ls_edge2msg(struct ls_message *msg, struct ls_edge *edge)
+{
+       /* Allocate space if needed */
+       if (msg == NULL)
+               msg = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_message));
+       else
+               memset(msg, 0, sizeof(*msg));
+
+       msg->type = LS_MSG_TYPE_ATTRIBUTES;
+       msg->data.attr = edge->attributes;
+       if (edge->destination != NULL)
+               msg->remote_id = edge->destination->node->adv;
+       else
+               msg->remote_id.origin = NONE;
+
+       return msg;
+}
+
+struct ls_message *ls_subnet2msg(struct ls_message *msg,
+                                struct ls_subnet *subnet)
+{
+       /* Allocate space if needed */
+       if (msg == NULL)
+               msg = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_message));
+       else
+               memset(msg, 0, sizeof(*msg));
+
+       msg->type = LS_MSG_TYPE_PREFIX;
+       msg->data.prefix = subnet->ls_pref;
+       msg->remote_id.origin = NONE;
+
+       return msg;
+}
+
+void ls_delete_msg(struct ls_message *msg)
+{
+       if (msg == NULL)
+               return;
+
+       switch (msg->type) {
+       case LS_MSG_TYPE_NODE:
+               if (msg->data.node)
+                       XFREE(MTYPE_LS_DB, msg->data.node);
+               break;
+       case LS_MSG_TYPE_ATTRIBUTES:
+               if (msg->data.attr)
+                       XFREE(MTYPE_LS_DB, msg->data.attr);
+               break;
+       case LS_MSG_TYPE_PREFIX:
+               if (msg->data.prefix)
+                       XFREE(MTYPE_LS_DB, msg->data.prefix);
+               break;
+       default:
+               break;
+       }
+
+       XFREE(MTYPE_LS_DB, msg);
+}
+
+int ls_sync_ted(struct ls_ted *ted, struct zclient *zclient,
+               struct zapi_opaque_reg_info *dst)
+{
+       struct ls_vertex *vertex;
+       struct ls_edge *edge;
+       struct ls_subnet *subnet;
+       struct ls_message msg;
+
+       /* Prepare message */
+       msg.event = LS_MSG_EVENT_SYNC;
+
+       /* Loop TED, start sending Node, then Attributes and finally Prefix */
+       frr_each(vertices, &ted->vertices, vertex) {
+               ls_vertex2msg(&msg, vertex);
+               ls_send_msg(zclient, &msg, dst);
+       }
+       frr_each(edges, &ted->edges, edge) {
+               ls_edge2msg(&msg, edge);
+               ls_send_msg(zclient, &msg, dst);
+       }
+       frr_each(subnets, &ted->subnets, subnet) {
+               ls_subnet2msg(&msg, subnet);
+               ls_send_msg(zclient, &msg, dst);
+       }
+       return 0;
+}
+
+void ls_dump_ted(struct ls_ted *ted)
+{
+       struct ls_vertex *vertex;
+       struct ls_edge *edge;
+       struct ls_subnet *subnet;
+       struct ls_message msg;
+
+       zlog_debug("(%s) Ted init", __func__);
+       /* Prepare message */
+       msg.event = LS_MSG_EVENT_SYNC;
+
+       /* Loop TED, start printing Node, then Attributes and finally Prefix */
+       frr_each(vertices, &ted->vertices, vertex) {
+               ls_vertex2msg(&msg, vertex);
+               zlog_debug("\tTed node (%s %pI4 %s)",
+                          vertex->node->name[0] ? vertex->node->name
+                                                : "no name node",
+                          &vertex->node->router_id,
+                          vertex->node->adv.origin == DIRECT ? "DIRECT"
+                                                             : "NO DIRECT");
+               struct listnode *lst_node;
+               struct ls_edge *vertex_edge;
+
+               for (ALL_LIST_ELEMENTS_RO(vertex->incoming_edges, lst_node,
+                                         vertex_edge)) {
+                       zlog_debug(
+                               "\t\tinc edge key:%lldn attr key:%pI4 loc:(%pI4) rmt:(%pI4)",
+                               vertex_edge->key,
+                               &vertex_edge->attributes->adv.id.ip.addr,
+                               &vertex_edge->attributes->standard.local,
+                               &vertex_edge->attributes->standard.remote);
+               }
+               for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, lst_node,
+                                         vertex_edge)) {
+                       zlog_debug(
+                               "\t\tout edge key:%lld  attr key:%pI4  loc:(%pI4) rmt:(%pI4)",
+                               vertex_edge->key,
+                               &vertex_edge->attributes->adv.id.ip.addr,
+                               &vertex_edge->attributes->standard.local,
+                               &vertex_edge->attributes->standard.remote);
+               }
+       }
+       frr_each(edges, &ted->edges, edge) {
+               ls_edge2msg(&msg, edge);
+               zlog_debug("\tTed edge key:%lld src:%s dst:%s", edge->key,
+                          edge->source ? edge->source->node->name
+                                       : "no_source",
+                          edge->destination ? edge->destination->node->name
+                                            : "no_dest");
+       }
+       frr_each(subnets, &ted->subnets, subnet) {
+               ls_subnet2msg(&msg, subnet);
+               zlog_debug(
+                       "\tTed subnet key:%s vertex:%pI4 pfx:%pFX",
+                       subnet->key.family == AF_INET
+                               ? inet_ntoa(subnet->key.u.prefix4)
+                               : inet6_ntoa(subnet->key.u.prefix6),
+                       &subnet->vertex->node->adv.id.ip.addr,
+                       &subnet->ls_pref->pref);
+       }
+       zlog_debug("(%s) Ted end", __func__);
+}
diff --git a/lib/link_state.h b/lib/link_state.h
new file mode 100644 (file)
index 0000000..93669f5
--- /dev/null
@@ -0,0 +1,780 @@
+/*
+ * Link State Database definition - ted.h
+ *
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ *
+ * Copyright (C) 2020 Orange http://www.orange.com
+ *
+ * This file is part of Free Range Routing (FRR).
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_LINK_STATE_H_
+#define _FRR_LINK_STATE_H_
+
+#include "typesafe.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * This file defines the model used to implement a Link State Database
+ * suitable to be used by various protocol like RSVP-TE, BGP-LS, PCEP ...
+ * This database is normally fulfill by the link state routing protocol,
+ * commonly OSPF or ISIS, carrying Traffic Engineering information within
+ * Link State Attributes. See, RFC3630.(OSPF-TE) and RFC5305 (ISIS-TE).
+ *
+ * At least, 3 types of Link State structure are defined:
+ *  - Link State Node that groups all information related to a node
+ *  - Link State Attributes that groups all information related to a link
+ *  - Link State Prefix that groups all information related to a prefix
+ *
+ * These 3 types of structures are those handled by BGP-LS (see RFC7752).
+ *
+ * Each structure, in addition to the specific parameters, embed the node
+ * identifier which advertises the Link State and a bit mask as flags to
+ * indicates which parameters are valid i.e. for which the value corresponds
+ * to a Link State information convey by the routing protocol.
+ * Node identifier is composed of the route id as IPv4 address plus the area
+ * id for OSPF and the ISO System id plus the IS-IS level for IS-IS.
+ */
+
+/* Link State Common definitions */
+#define MAX_NAME_LENGTH                256
+#define ISO_SYS_ID_LEN         6
+
+/* Type of Node */
+enum ls_node_type {
+       STANDARD,       /* a P or PE node */
+       ABR,            /* an Array Border Node */
+       ASBR,           /* an Autonomous System Border Node */
+       PSEUDO,         /* a Pseudo Node */
+};
+
+/* Origin of the Link State information */
+enum ls_origin {NONE = 0, ISIS_L1, ISIS_L2, OSPFv2, DIRECT, STATIC};
+
+/**
+ * Link State Node Identifier as:
+ *  - IPv4 address + Area ID for OSPF
+ *  - ISO System ID + ISIS Level for ISIS
+ */
+struct ls_node_id {
+       enum ls_origin origin;          /* Origin of the LS information */
+       union {
+               struct {
+                       struct in_addr addr;            /* OSPF Router IS */
+                       struct in_addr area_id;         /* OSPF Area ID */
+               } ip;
+               struct {
+                       uint8_t sys_id[ISO_SYS_ID_LEN]; /* ISIS System ID */
+                       uint8_t level;                  /* ISIS Level */
+                       uint8_t padding;
+               } iso;
+       } id __attribute__((aligned(8)));
+};
+
+/* Link State flags to indicate which Node parameters are valid */
+#define LS_NODE_UNSET          0x0000
+#define LS_NODE_NAME           0x0001
+#define LS_NODE_ROUTER_ID      0x0002
+#define LS_NODE_ROUTER_ID6     0x0004
+#define LS_NODE_FLAG           0x0008
+#define LS_NODE_TYPE           0x0010
+#define LS_NODE_AS_NUMBER      0x0020
+#define LS_NODE_SR             0x0040
+#define LS_NODE_SRLB           0x0080
+#define LS_NODE_MSD            0x0100
+
+/* Link State Node structure */
+struct ls_node {
+       uint16_t flags;                 /* Flag for parameters validity */
+       struct ls_node_id adv;          /* Adv. Router of this Link State */
+       char name[MAX_NAME_LENGTH];     /* Name of the Node (IS-IS only) */
+       struct in_addr router_id;       /* IPv4 Router ID */
+       struct in6_addr router6_id;     /* IPv6 Router ID */
+       uint8_t node_flag;              /* IS-IS or OSPF Node flag */
+       enum node_type type;            /* Type of Node */
+       uint32_t as_number;             /* Local or neighbor AS number */
+       struct {                        /* Segment Routing Global Block */
+               uint32_t lower_bound;           /* MPLS label lower bound */
+               uint32_t range_size;            /* MPLS label range size */
+               uint8_t flag;                   /* IS-IS SRGB flags */
+       } srgb;
+#define LS_NODE_SRGB_SIZE      9
+       struct {                        /* Segment Routing Local Block */
+               uint32_t lower_bound;           /* MPLS label lower bound */
+               uint32_t range_size;            /* MPLS label range size */
+       } srlb;
+#define LS_NODE_SRLB_SIZE      8
+       uint8_t algo[2];                /* Segment Routing Algorithms */
+       uint8_t msd;                    /* Maximum Stack Depth */
+};
+
+/* Link State flags to indicate which Attribute parameters are valid */
+#define LS_ATTR_UNSET          0x00000000
+#define LS_ATTR_NAME           0x00000001
+#define LS_ATTR_METRIC         0x00000002
+#define LS_ATTR_TE_METRIC      0x00000004
+#define LS_ATTR_ADM_GRP                0x00000008
+#define LS_ATTR_LOCAL_ADDR     0x00000010
+#define LS_ATTR_NEIGH_ADDR     0x00000020
+#define LS_ATTR_LOCAL_ADDR6    0x00000040
+#define LS_ATTR_NEIGH_ADDR6    0x00000080
+#define LS_ATTR_LOCAL_ID       0x00000100
+#define LS_ATTR_NEIGH_ID       0x00000200
+#define LS_ATTR_MAX_BW         0x00000400
+#define LS_ATTR_MAX_RSV_BW     0x00000800
+#define LS_ATTR_UNRSV_BW       0x00001000
+#define LS_ATTR_REMOTE_AS      0x00002000
+#define LS_ATTR_REMOTE_ADDR    0x00004000
+#define LS_ATTR_REMOTE_ADDR6   0x00008000
+#define LS_ATTR_DELAY          0x00010000
+#define LS_ATTR_MIN_MAX_DELAY  0x00020000
+#define LS_ATTR_JITTER         0x00040000
+#define LS_ATTR_PACKET_LOSS    0x00080000
+#define LS_ATTR_AVA_BW         0x00100000
+#define LS_ATTR_RSV_BW         0x00200000
+#define LS_ATTR_USE_BW         0x00400000
+#define LS_ATTR_ADJ_SID                0x00800000
+#define LS_ATTR_BCK_ADJ_SID    0x01000000
+#define LS_ATTR_SRLG           0x02000000
+
+/* Link State Attributes */
+struct ls_attributes {
+       uint32_t flags;                 /* Flag for parameters validity */
+       struct ls_node_id adv;          /* Adv. Router of this Link State */
+       char name[MAX_NAME_LENGTH];     /* Name of the Edge. Could be null */
+       struct {                        /* Standard TE metrics */
+               uint32_t metric;                /* IGP standard metric */
+               uint32_t te_metric;             /* Traffic Engineering metric */
+               uint32_t admin_group;           /* Administrative Group */
+               struct in_addr local;           /* Local IPv4 address */
+               struct in_addr remote;          /* Remote IPv4 address */
+               struct in6_addr local6;         /* Local IPv6 address */
+               struct in6_addr remote6;        /* Remote IPv6 address */
+               uint32_t local_id;              /* Local Identifier */
+               uint32_t remote_id;             /* Remote Identifier */
+               float max_bw;                   /* Maximum Link Bandwidth */
+               float max_rsv_bw;               /* Maximum Reservable BW */
+               float unrsv_bw[8];              /* Unreserved BW per CT (8) */
+               uint32_t remote_as;             /* Remote AS number */
+               struct in_addr remote_addr;     /* Remote IPv4 address */
+               struct in6_addr remote_addr6;   /* Remote IPv6 address */
+       } standard;
+#define LS_ATTR_STANDARD_SIZE  124
+       struct {                /* Extended TE Metrics */
+               uint32_t delay;         /* Unidirectional average delay */
+               uint32_t min_delay;     /* Unidirectional minimum delay */
+               uint32_t max_delay;     /* Unidirectional maximum delay */
+               uint32_t jitter;        /* Unidirectional delay variation */
+               uint32_t pkt_loss;      /* Unidirectional packet loss */
+               float ava_bw;           /* Available Bandwidth */
+               float rsv_bw;           /* Reserved Bandwidth */
+               float used_bw;          /* Utilized Bandwidth */
+       } extended;
+#define LS_ATTR_EXTENDED_SIZE  32
+       struct {                /* (LAN)-Adjacency SID for OSPF */
+               uint32_t sid;           /* SID as MPLS label or index */
+               uint8_t flags;          /* Flags */
+               uint8_t weight;         /* Administrative weight */
+               union {
+                       struct in_addr addr;    /* Neighbor @IP for OSPF */
+                       uint8_t sysid[ISO_SYS_ID_LEN]; /* or Sys-ID for ISIS */
+               } neighbor;
+       } adj_sid[2];           /* Primary & Backup (LAN)-Adj. SID */
+#define LS_ATTR_ADJ_SID_SIZE   120
+       uint32_t *srlgs;        /* List of Shared Risk Link Group */
+       uint8_t srlg_len;       /* number of SRLG in the list */
+};
+
+/* Link State flags to indicate which Prefix parameters are valid */
+#define LS_PREF_UNSET          0x00
+#define LS_PREF_IGP_FLAG       0x01
+#define LS_PREF_ROUTE_TAG      0x02
+#define LS_PREF_EXTENDED_TAG   0x04
+#define LS_PREF_METRIC         0x08
+#define LS_PREF_SR             0x10
+
+/* Link State Prefix */
+struct ls_prefix {
+       uint8_t flags;                  /* Flag for parameters validity */
+       struct ls_node_id adv;          /* Adv. Router of this Link State */
+       struct prefix pref;             /* IPv4 or IPv6 prefix */
+       uint8_t igp_flag;               /* IGP Flags associated to the prefix */
+       uint32_t route_tag;             /* IGP Route Tag */
+       uint64_t extended_tag;          /* IGP Extended Route Tag */
+       uint32_t metric;                /* Route metric for this prefix */
+       struct {
+               uint32_t sid;           /* Segment Routing ID */
+               uint8_t sid_flag;       /* Segment Routing Flags */
+               uint8_t algo;           /* Algorithm for Segment Routing */
+       } sr;
+};
+
+/**
+ * Create a new Link State Node. Structure is dynamically allocated.
+ *
+ * @param adv  Mandatory Link State Node ID i.e. advertise router information
+ * @param rid  Router ID as IPv4 address
+ * @param rid6 Router ID as IPv6 address
+ *
+ * @return     New Link State Node
+ */
+extern struct ls_node *ls_node_new(struct ls_node_id adv, struct in_addr rid,
+                                  struct in6_addr rid6);
+
+/**
+ * Remove Link State Node. Data structure is freed.
+ *
+ * @param node       Pointer to a valid Link State Node structure
+ */
+extern void ls_node_del(struct ls_node *node);
+
+/**
+ * Check if two Link State Nodes are equal. Note that this routine has the same
+ * return value sense as '==' (which is different from a comparison).
+ *
+ * @param n1   First Link State Node to be compare
+ * @param n2   Second Link State Node to be compare
+ *
+ * @return     1 if equal, 0 otherwise
+ */
+extern int ls_node_same(struct ls_node *n1, struct ls_node *n2);
+
+/**
+ * Create a new Link State Attributes. Structure is dynamically allocated.
+ * At least one of parameters MUST be valid and not equal to 0.
+ *
+ * @param adv          Mandatory Link State Node ID i.e. advertise router ID
+ * @param local                Local IPv4 address
+ * @param local6       Local Ipv6 address
+ * @param local_id     Local Identifier
+ *
+ * @return             New Link State Attributes
+ */
+extern struct ls_attributes *ls_attributes_new(struct ls_node_id adv,
+                                              struct in_addr local,
+                                              struct in6_addr local6,
+                                              uint32_t local_id);
+
+/**
+ * Remove Link State Attributes. Data structure is freed.
+ *
+ * @param attr          Pointer to a valid Link State Attribute structure
+ */
+extern void ls_attributes_del(struct ls_attributes *attr);
+
+/**
+ * Check if two Link State Attributes are equal. Note that this routine has the
+ * same return value sense as '==' (which is different from a comparison).
+ *
+ * @param a1   First Link State Attributes to be compare
+ * @param a2   Second Link State Attributes to be compare
+ *
+ * @return     1 if equal, 0 otherwise
+ */
+extern int ls_attributes_same(struct ls_attributes *a1,
+                             struct ls_attributes *a2);
+
+/**
+ * In addition a Graph model is defined as an overlay on top of link state
+ * database in order to ease Path Computation algorithm implementation.
+ * Denoted G(V, E), a graph is composed by a list of Vertices (V) which
+ * represents the network Node and a list of Edges (E) which represents node
+ * Link. An additional list of prefixes (P) is also added.
+ * A prefix (P) is also attached to the Vertex (V) which advertise it.
+ *
+ * Vertex (V) contains the list of outgoing Edges (E) that connect this Vertex
+ * with its direct neighbors and the list of incoming Edges (E) that connect
+ * the direct neighbors to this Vertex. Indeed, the Edge (E) is unidirectional,
+ * thus, it is necessary to add 2 Edges to model a bidirectional relation
+ * between 2 Vertices.
+ *
+ * Edge (E) contains the source and destination Vertex that this Edge
+ * is connecting.
+ *
+ * A unique Key is used to identify both Vertices and Edges within the Graph.
+ * An easy way to build this key is to used the IP address: i.e. loopback
+ * address for Vertices and link IP address for Edges.
+ *
+ *      --------------     ---------------------------    --------------
+ *      | Connected  |---->| Connected Edge Va to Vb |--->| Connected  |
+ *  --->|  Vertex    |     ---------------------------    |  Vertex    |---->
+ *      |            |                                    |            |
+ *      | - Key (Va) |                                    | - Key (Vb) |
+ *  <---| - Vertex   |     ---------------------------    | - Vertex   |<----
+ *      |            |<----| Connected Edge Vb to Va |<---|            |
+ *      --------------     ---------------------------    --------------
+ *
+ */
+
+/* Link State Vertex structure */
+PREDECL_RBTREE_UNIQ(vertices)
+struct ls_vertex {
+       struct vertices_item entry;     /* Entry in RB Tree */
+       uint64_t key;                   /* Unique Key identifier */
+       struct ls_node *node;           /* Link State Node */
+       struct list *incoming_edges;    /* List of incoming Link State links */
+       struct list *outgoing_edges;    /* List of outgoing Link State links */
+       struct list *prefixes;          /* List of advertised prefix */
+};
+
+/* Link State Edge structure */
+PREDECL_RBTREE_UNIQ(edges)
+struct ls_edge {
+       struct edges_item entry;        /* Entry in RB tree */
+       uint64_t key;                   /* Unique Key identifier */
+       struct ls_attributes *attributes;       /* Link State attributes */
+       struct ls_vertex *source;       /* Pointer to the source Vertex */
+       struct ls_vertex *destination;  /* Pointer to the destination Vertex */
+};
+
+/* Link State Subnet structure */
+PREDECL_RBTREE_UNIQ(subnets)
+struct ls_subnet {
+       struct subnets_item entry;      /* Entry in RB tree */
+       struct prefix key;              /* Unique Key identifier */
+       struct ls_vertex *vertex;       /* Back pointer to the Vertex owner */
+       struct ls_prefix *ls_pref;      /* Link State Prefix */
+};
+
+/* Declaration of Vertices, Edges and Prefixes RB Trees */
+macro_inline int vertex_cmp(const struct ls_vertex *node1,
+                           const struct ls_vertex *node2)
+{
+       return (node1->key - node2->key);
+}
+DECLARE_RBTREE_UNIQ(vertices, struct ls_vertex, entry, vertex_cmp)
+
+macro_inline int edge_cmp(const struct ls_edge *edge1,
+                         const struct ls_edge *edge2)
+{
+       return (edge1->key - edge2->key);
+}
+DECLARE_RBTREE_UNIQ(edges, struct ls_edge, entry, edge_cmp)
+
+macro_inline int subnet_cmp(const struct ls_subnet *a,
+                            const struct ls_subnet *b)
+{
+       return prefix_cmp(&a->key, &b->key);
+}
+DECLARE_RBTREE_UNIQ(subnets, struct ls_subnet, entry, subnet_cmp)
+
+/* Link State TED Structure */
+struct ls_ted {
+       uint32_t key;                   /* Unique identifier */
+       char name[MAX_NAME_LENGTH];     /* Name of this graph. Could be null */
+       uint32_t as_number;             /* AS number of the modeled network */
+       struct ls_vertex *self;         /* Vertex of the FRR instance */
+       struct vertices_head vertices;  /* List of Vertices */
+       struct edges_head edges;        /* List of Edges */
+       struct subnets_head subnets;    /* List of Subnets */
+};
+
+/**
+ * Create a new Link State Vertex structure and initialize is with the Link
+ * State Node parameter.
+ *
+ * @param node Link State Node
+ *
+ * @return     New Vertex
+ */
+extern struct ls_vertex *ls_vertex_new(struct ls_node *node);
+
+/**
+ * Delete Link State Vertex. This function clean internal Vertex lists (incoming
+ * and outgoing Link State Edge and Link State Subnet). Note that referenced
+ * objects of the different lists (Edges & SubNet) are not removed as they could
+ * be connected to other Vertices.
+ *
+ * @param vertex       Link State Vertex to be removed
+ */
+extern void ls_vertex_del(struct ls_vertex *vertex);
+
+/**
+ * Add new vertex to the Link State DB. Vertex is created from the Link State
+ * Node. Vertex data structure is dynamically allocated.
+ *
+ * @param ted  Traffic Engineering Database structure
+ * @param node Link State Node
+ *
+ * @return     New Vertex or NULL in case of error
+ */
+extern struct ls_vertex *ls_vertex_add(struct ls_ted *ted,
+                                      struct ls_node *node);
+
+/**
+ * Update Vertex with the Link State Node. A new vertex is created if no one
+ * corresponds to the Link State Node.
+ *
+ * @param ted  Link State Data Base
+ * @param node Link State Node to be updated
+ *
+ * @return     Updated Link State Vertex or Null in case of error
+ */
+extern struct ls_vertex *ls_vertex_update(struct ls_ted *ted,
+                                         struct ls_node *node);
+
+/**
+ * Remove Vertex from the Link State DB. Vertex Data structure is freed but
+ * not the Link State Node. Link State DB is not modified if Vertex is NULL or
+ * not found in the Data Base.
+ *
+ * @param ted          Link State Data Base
+ * @param vertex       Vertex to be removed
+ */
+extern void ls_vertex_remove(struct ls_ted *ted, struct ls_vertex *vertex);
+
+/**
+ * Find Vertex in the Link State DB by its unique key.
+ *
+ * @param ted  Link State Data Base
+ * @param key  Vertex Key different from 0
+ *
+ * @return     Vertex if found, NULL otherwise
+ */
+extern struct ls_vertex *ls_find_vertex_by_key(struct ls_ted *ted,
+                                              const uint64_t key);
+
+/**
+ * Find Vertex in the Link State DB by its Link State Node.
+ *
+ * @param ted  Link State Data Base
+ * @param nid  Link State Node ID
+ *
+ * @return     Vertex if found, NULL otherwise
+ */
+extern struct ls_vertex *ls_find_vertex_by_id(struct ls_ted *ted,
+                                             struct ls_node_id nid);
+
+/**
+ * Check if two Vertices are equal. Note that this routine has the same return
+ * value sense as '==' (which is different from a comparison).
+ *
+ * @param v1   First vertex to compare
+ * @param v2   Second vertex to compare
+ *
+ * @return     1 if equal, 0 otherwise
+ */
+extern int ls_vertex_same(struct ls_vertex *v1, struct ls_vertex *v2);
+
+/**
+ * Add new Edge to the Link State DB. Edge is created from the Link State
+ * Attributes. Edge data structure is dynamically allocated.
+ *
+ * @param ted          Link State Data Base
+ * @param attributes   Link State attributes
+ *
+ * @return             New Edge or NULL in case of error
+ */
+extern struct ls_edge *ls_edge_add(struct ls_ted *ted,
+                                  struct ls_attributes *attributes);
+
+/**
+ * Update the Link State Attributes information of an existing Edge. If there is
+ * no corresponding Edge in the Link State Data Base, a new Edge is created.
+ *
+ * @param ted          Link State Data Base
+ * @param attributes   Link State Attributes
+ *
+ * @return             Updated Link State Edge, or NULL in case of error
+ */
+extern struct ls_edge *ls_edge_update(struct ls_ted *ted,
+                                     struct ls_attributes *attributes);
+
+/**
+ * Remove Edge from the Link State DB. Edge data structure is freed but not the
+ * Link State Attributes data structure. Link State DB is not modified if Edge
+ * is NULL or not found in the Data Base.
+ *
+ * @param ted  Link State Data Base
+ * @param edge Edge to be removed
+ */
+extern void ls_edge_del(struct ls_ted *ted, struct ls_edge *edge);
+
+/**
+ * Find Edge in the Link State Data Base by Edge key.
+ *
+ * @param ted  Link State Data Base
+ * @param key  Edge key
+ *
+ * @return     Edge if found, NULL otherwise
+ */
+extern struct ls_edge *ls_find_edge_by_key(struct ls_ted *ted,
+                                          const uint64_t key);
+
+/**
+ * Find Edge in the Link State Data Base by the source (local IPv4 or IPv6
+ * address or local ID) informations of the Link
+ * State Attributes
+ *
+ * @param ted          Link State Data Base
+ * @param attributes   Link State Attributes
+ *
+ * @return             Edge if found, NULL otherwise
+ */
+extern struct ls_edge *
+ls_find_edge_by_source(struct ls_ted *ted, struct ls_attributes *attributes);
+
+/**
+ * Find Edge in the Link State Data Base by the destination (remote IPv4 or IPv6
+ * address of remote ID) information of the Link State Attributes
+ *
+ * @param ted          Link State Data Base
+ * @param attributes   Link State Attributes
+ *
+ * @return             Edge if found, NULL otherwise
+ */
+extern struct ls_edge *
+ls_find_edge_by_destination(struct ls_ted *ted,
+                           struct ls_attributes *attributes);
+
+/**
+ * Add new Subnet to the Link State DB. Subnet is created from the Link State
+ * prefix. Subnet data structure is dynamically allocated.
+ *
+ * @param ted  Link State Data Base
+ * @param pref Link State Prefix
+ *
+ * @return     New Subnet
+ */
+extern struct ls_subnet *ls_subnet_add(struct ls_ted *ted,
+                                      struct ls_prefix *pref);
+
+/**
+ * Remove Subnet from the Link State DB. Subnet data structure is freed but
+ * not the Link State prefix data structure. Link State DB is not modified
+ * if Subnet is NULL or not found in the Data Base.
+ *
+ * @param ted          Link State Data Base
+ * @param subnet       Subnet to be removed
+ */
+extern void ls_subnet_del(struct ls_ted *ted, struct ls_subnet *subnet);
+
+/**
+ * Find Subnet in the Link State Data Base by prefix.
+ *
+ * @param ted          Link State Data Base
+ * @param prefix       Link State Prefix
+ *
+ * @return             Subnet if found, NULL otherwise
+ */
+extern struct ls_subnet *ls_find_subnet(struct ls_ted *ted,
+                                       const struct prefix prefix);
+
+/**
+ * Create a new Link State Data Base.
+ *
+ * @param key  Unique key of the data base. Must be different from 0
+ * @param name Name of the data base (may be NULL)
+ * @param asn  AS Number for this data base. Must be different from 0
+ *
+ * @return     New Link State Database or NULL in case of error
+ */
+extern struct ls_ted *ls_ted_new(const uint32_t key, const char *name,
+                                uint32_t asn);
+
+/**
+ * Delete existing Link State Data Base.
+ *
+ * @param ted  Link State Data Base
+ */
+extern void ls_ted_del(struct ls_ted *ted);
+
+/**
+ * Connect Source and Destination Vertices by given Edge. Only non NULL source
+ * and destination vertices are connected.
+ *
+ * @param src  Link State Source Vertex
+ * @param dst  Link State Destination Vertex
+ * @param edge Link State Edge. Must not be NULL
+ */
+extern void ls_connect_vertices(struct ls_vertex *src, struct ls_vertex *dst,
+                               struct ls_edge *edge);
+
+/**
+ * Connect Link State Edge to the Link State Vertex which could be a Source or
+ * a Destination Vertex.
+ *
+ * @param vertex       Link State Vertex to be connected. Must not be NULL
+ * @param edge         Link State Edge connection. Must not be NULL
+ * @param source       True for a Source, false for a Destination Vertex
+ */
+extern void ls_connect(struct ls_vertex *vertex, struct ls_edge *edge,
+                      bool source);
+
+/**
+ * Disconnect Link State Edge from the Link State Vertex which could be a
+ * Source or a Destination Vertex.
+ *
+ * @param vertex       Link State Vertex to be connected. Must not be NULL
+ * @param edge         Link State Edge connection. Must not be NULL
+ * @param source       True for a Source, false for a Destination Vertex
+ */
+extern void ls_disconnect(struct ls_vertex *vertex, struct ls_edge *edge,
+                         bool source);
+
+/**
+ * Disconnect Link State Edge from both Source and Destination Vertex.
+ *
+ * @param edge         Link State Edge to be disconnected
+ */
+extern void ls_disconnect_edge(struct ls_edge *edge);
+
+
+/**
+ * The Link State Message is defined to convey Link State parameters from
+ * the routing protocol (OSPF or IS-IS) to other daemons e.g. BGP.
+ *
+ * The structure is composed of:
+ *  - Event of the message:
+ *    - Sync: Send the whole LS DB following a request
+ *    - Add: Send the a new Link State element
+ *    -  Update: Send an update of an existing Link State element
+ *    - Delete: Indicate that the given Link State element is removed
+ *  - Type of Link State element: Node, Attribute or Prefix
+ *  - Remote node id when known
+ *  - Data: Node, Attributes or Prefix
+ *
+ * A Link State Message can carry only one Link State Element (Node, Attributes
+ * of Prefix) at once, and only one Link State Message is sent through ZAPI
+ * Opaque Link State type at once.
+ */
+
+/* ZAPI Opaque Link State Message Event */
+#define LS_MSG_EVENT_SYNC      1
+#define LS_MSG_EVENT_ADD       2
+#define LS_MSG_EVENT_UPDATE    3
+#define LS_MSG_EVENT_DELETE    4
+
+/* ZAPI Opaque Link State Message sub-Type */
+#define LS_MSG_TYPE_NODE       1
+#define LS_MSG_TYPE_ATTRIBUTES 2
+#define LS_MSG_TYPE_PREFIX     3
+
+/* Link State Message */
+struct ls_message {
+       uint8_t event;          /* Message Event: Sync, Add, Update, Delete */
+       uint8_t type;           /* Message Data Type: Node, Attribute, Prefix */
+       struct ls_node_id remote_id;    /* Remote Link State Node ID */
+       union {
+               struct ls_node *node;           /* Link State Node */
+               struct ls_attributes *attr;     /* Link State Attributes */
+               struct ls_prefix *prefix;       /* Link State Prefix */
+       } data;
+};
+
+/**
+ * Parse Link State Message from stream. Used this function once receiving a
+ * new ZAPI Opaque message of type Link State.
+ *
+ * @param s    Stream buffer. Must not be NULL.
+ *
+ * @return     New Link State Message or NULL in case of error
+ */
+extern struct ls_message *ls_parse_msg(struct stream *s);
+
+/**
+ * Delete existing message, freeing all substructure.
+ *
+ * @param msg  Link state message to be deleted
+ */
+extern void ls_delete_msg(struct ls_message *msg);
+
+/**
+ * Send Link State Message as new ZAPI Opaque message of type Link State.
+ * If destination is not NULL, message is sent as Unicast otherwise it is
+ * broadcast to all registered daemon.
+ *
+ * @param zclient      Zebra Client
+ * @param msg          Link State Message to be sent
+ * @param dst          Destination daemon for unicast message,
+ *                     NULL for broadcast message
+ *
+ * @return             0 on success, -1 otherwise
+ */
+extern int ls_send_msg(struct zclient *zclient, struct ls_message *msg,
+                      struct zapi_opaque_reg_info *dst);
+
+/**
+ * Create a new Link State Message from a Link State Vertex. If Link State
+ * Message is NULL, a new data structure is dynamically allocated.
+ *
+ * @param msg          Link State Message to be filled or NULL
+ * @param vertex       Link State Vertex. Must not be NULL
+ *
+ * @return             New Link State Message msg parameter is NULL or pointer
+ *                     to the provided Link State Message
+ */
+extern struct ls_message *ls_vertex2msg(struct ls_message *msg,
+                                       struct ls_vertex *vertex);
+
+/**
+ * Create a new Link State Message from a Link State Edge. If Link State
+ * Message is NULL, a new data structure is dynamically allocated.
+ *
+ * @param msg          Link State Message to be filled or NULL
+ * @param edge         Link State Edge. Must not be NULL
+ *
+ * @return             New Link State Message msg parameter is NULL or pointer
+ *                     to the provided Link State Message
+ */
+extern struct ls_message *ls_edge2msg(struct ls_message *msg,
+                                     struct ls_edge *edge);
+
+/**
+ * Create a new Link State Message from a Link State Subnet. If Link State
+ * Message is NULL, a new data structure is dynamically allocated.
+ *
+ * @param msg          Link State Message to be filled or NULL
+ * @param subnet       Link State Subnet. Must not be NULL
+ *
+ * @return             New Link State Message msg parameter is NULL or pointer
+ *                     to the provided Link State Message
+ */
+extern struct ls_message *ls_subnet2msg(struct ls_message *msg,
+                                       struct ls_subnet *subnet);
+
+/**
+ * Send all the content of the Link State Data Base to the given destination.
+ * Link State content is sent is this order: Vertices, Edges, Subnet.
+ * This function must be used when a daemon request a Link State Data Base
+ * Synchronization.
+ *
+ * @param ted          Link State Data Base. Must not be NULL
+ * @param zclient      Zebra Client. Must not be NULL
+ * @param dst          Destination FRR daemon. Must not be NULL
+ *
+ * @return             0 on success, -1 otherwise
+ */
+extern int ls_sync_ted(struct ls_ted *ted, struct zclient *zclient,
+                      struct zapi_opaque_reg_info *dst);
+
+/**
+ * Dump all Link State Data Base elements for debugging purposes
+ *
+ * @param ted  Link State Data Base. Must not be NULL
+ *
+ */
+extern void ls_dump_ted(struct ls_ted *ted);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_LINK_STATE_H_ */
index 7b37ba7f27e9e2716f5cffd9a816f1eb4637c839..03ed23a04bcecf2bf221d450d6e604260a995f7b 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -456,7 +456,8 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_NHG_ADD),
        DESC_ENTRY(ZEBRA_NHG_DEL),
        DESC_ENTRY(ZEBRA_NHG_NOTIFY_OWNER),
-       DESC_ENTRY(ZEBRA_ROUTE_NOTIFY_REQUEST)};
+       DESC_ENTRY(ZEBRA_ROUTE_NOTIFY_REQUEST),
+       DESC_ENTRY(ZEBRA_CLIENT_CLOSE_NOTIFY)};
 #undef DESC_ENTRY
 
 static const struct zebra_desc_table unknown = {0, "unknown", '?'};
index f715044ea302c2ef6766be310518c4072830d4e2..a377d3b945e0047b36ce5ad1825acb8d11c590ae 100644 (file)
@@ -127,6 +127,12 @@ void *qstrdup(struct memtype *mt, const char *str)
        return str ? mt_checkalloc(mt, strdup(str), strlen(str) + 1) : NULL;
 }
 
+void qcountfree(struct memtype *mt, void *ptr)
+{
+       if (ptr)
+               mt_count_free(mt, ptr);
+}
+
 void qfree(struct memtype *mt, void *ptr)
 {
        if (ptr)
index 13f2f9b11ac06dcc7a59d26d75760e275ed90c6e..e9db12fce2ca85738165df3a7c9b4e0fba6f3d03 100644 (file)
@@ -162,12 +162,15 @@ extern void *qrealloc(struct memtype *mt, void *ptr, size_t size)
        __attribute__((_ALLOC_SIZE(3), nonnull(1) _RET_NONNULL));
 extern void *qstrdup(struct memtype *mt, const char *str)
        __attribute__((malloc, nonnull(1) _RET_NONNULL));
+extern void qcountfree(struct memtype *mt, void *ptr)
+       __attribute__((nonnull(1)));
 extern void qfree(struct memtype *mt, void *ptr) __attribute__((nonnull(1)));
 
 #define XMALLOC(mtype, size)           qmalloc(mtype, size)
 #define XCALLOC(mtype, size)           qcalloc(mtype, size)
 #define XREALLOC(mtype, ptr, size)     qrealloc(mtype, ptr, size)
 #define XSTRDUP(mtype, str)            qstrdup(mtype, str)
+#define XCOUNTFREE(mtype, ptr)         qcountfree(mtype, ptr)
 #define XFREE(mtype, ptr)                                                      \
        do {                                                                   \
                qfree(mtype, ptr);                                             \
index 3f6e4dc46e5a7af494d904bcee60a5181994c91e..8dd6b4c33751f5944f1f3bd6d2b6aa4e1512e0c4 100644 (file)
@@ -552,7 +552,7 @@ struct nb_node {
  * from working properly on shared libraries. For those compilers, use a fixed
  * size array to work around the problem.
  */
-#define YANG_MODULE_MAX_NODES 1400
+#define YANG_MODULE_MAX_NODES 2000
 
 struct frr_yang_module_info {
        /* YANG module name. */
@@ -600,6 +600,7 @@ enum nb_client {
        NB_CLIENT_CONFD,
        NB_CLIENT_SYSREPO,
        NB_CLIENT_GRPC,
+       NB_CLIENT_PCEP,
 };
 
 /* Northbound context. */
@@ -621,6 +622,8 @@ struct nb_context {
                } sysrepo;
                struct {
                } grpc;
+               struct {
+               } pcep;
        } client_data;
 #endif
 };
index 7048df99fba4b09470620fb454f32ce225169c36..853f6434721255f5c976e2a0759d68163b01f767 100644 (file)
@@ -693,6 +693,12 @@ static int nb_write_config(struct nb_config *config, enum nb_cfg_format format,
                          __func__, safe_strerror(errno));
                return -1;
        }
+       if (fchmod(fd, CONFIGFILE_MASK) != 0) {
+               flog_warn(EC_LIB_SYSTEM_CALL,
+                         "%s: fchmod() failed: %s(%d):", __func__,
+                         safe_strerror(errno), errno);
+               return -1;
+       }
 
        /* Make vty for configuration file. */
        file_vty = vty_new();
index d2cabf3104dd712f2f04c6476cdedb322d85d9ea..b7fdc263694f5920384495340e25764d11d9917c 100644 (file)
@@ -479,7 +479,7 @@ extern void apply_mask_ipv4(struct prefix_ipv4 *);
 #define PREFIX_COPY(DST, SRC)                                                  \
        *((struct prefix *)(DST)) = *((const struct prefix *)(SRC))
 #define PREFIX_COPY_IPV4(DST, SRC)                                             \
-       *((struct prefix_ipv4 *)(DST)) = *((const struct prefix_ipv4 *)(SRC));
+       *((struct prefix_ipv4 *)(DST)) = *((const struct prefix_ipv4 *)(SRC))
 
 extern int prefix_ipv4_any(const struct prefix_ipv4 *);
 extern void apply_classful_mask_ipv4(struct prefix_ipv4 *);
@@ -499,7 +499,7 @@ extern int str2prefix_ipv6(const char *, struct prefix_ipv6 *);
 extern void apply_mask_ipv6(struct prefix_ipv6 *);
 
 #define PREFIX_COPY_IPV6(DST, SRC)                                             \
-       *((struct prefix_ipv6 *)(DST)) = *((const struct prefix_ipv6 *)(SRC));
+       *((struct prefix_ipv6 *)(DST)) = *((const struct prefix_ipv6 *)(SRC))
 
 extern int ip6_masklen(struct in6_addr);
 extern void masklen2ip6(const int, struct in6_addr *);
index 39af8d0d5637bb0f76ba4360ff5b1c407d2cc336..759e9b47296bc7fb3d9619f60d33d2d48d561bc0 100755 (executable)
@@ -29,6 +29,7 @@
 ##
 
 use strict;
+use Getopt::Long;
 
 # input processing
 #
@@ -37,6 +38,11 @@ my %protodetail;
 
 my %daemons;
 
+my @enabled;
+
+GetOptions ("enabled=s" => \@enabled);
+@enabled = split(/,/,join(',',@enabled));
+
 while (<STDIN>) {
        # skip comments and empty lines
        next if (/^\s*(#|$)/);
@@ -56,7 +62,7 @@ while (<STDIN>) {
 
        # else: 8-field line
        my @f = split(/,/, $_);
-       unless (@f == 8 || @f == 9) {
+       unless (@f == 9 || @f == 10) {
                die "invalid input on route_types line $.\n";
        }
 
@@ -74,7 +80,8 @@ while (<STDIN>) {
                "ipv6" => int($f[5]),
                "redist" => int($f[6]),
                "shorthelp" => $f[7],
-               "restrict2" => $f[8],
+               "enabled" => $f[8],
+               "restrict2" => $f[9],
        };
        push @protos, $proto;
        $daemons{$f[2]} = {
@@ -109,6 +116,7 @@ sub codelist {
        my (@lines) = ();
        my $str = "  \"Codes: ";
        for my $p (@protos) {
+               next unless (grep $_ eq $protodetail{$p}->{"enabled"}, @enabled);
                my $s = sprintf("%s - %s, ",
                        $protodetail{$p}->{"char"},
                        $protodetail{$p}->{"shorthelp"});
@@ -141,6 +149,7 @@ sub collect {
                next if ($protodetail{$p}->{"restrict2"} ne "" && 
                         $protodetail{$p}->{"restrict2"} ne $daemon);
                next if ($protodetail{$p}->{"redist"} eq 0);
+               next unless (grep $_ eq $protodetail{$p}->{"enabled"}, @enabled);
                next unless (($ipv4 && $protodetail{$p}->{"ipv4"})
                             || ($ipv6 && $protodetail{$p}->{"ipv6"}));
                push @names, $protodetail{$p}->{"cname"};
index 37cc2fb5903475e39e2265edc5839955e5e264c6..c48391545d0f4a36098ae9929f8d7b0191fd2e47 100644 (file)
 # If you add a new routing protocol here, make sure you also update
 # meta_queue_map in zebra_rib.c
 #
-##  type                cname      daemon  C    4  6  Redist short help  Restrictions
-ZEBRA_ROUTE_SYSTEM,     system,    NULL,   'X', 0, 0, 0,     "Reserved"
-ZEBRA_ROUTE_KERNEL,     kernel,    zebra,  'K', 1, 1, 1,     "kernel route"
-ZEBRA_ROUTE_CONNECT,    connected, zebra,  'C', 1, 1, 1,     "connected"
-ZEBRA_ROUTE_STATIC,     static,    zebra,  'S', 1, 1, 1,     "static"
-ZEBRA_ROUTE_RIP,        rip,       ripd,   'R', 1, 0, 1,     "RIP"
-ZEBRA_ROUTE_RIPNG,      ripng,     ripngd, 'R', 0, 1, 1,     "RIPng"
-ZEBRA_ROUTE_OSPF,       ospf,      ospfd,  'O', 1, 0, 1,     "OSPF"
-ZEBRA_ROUTE_OSPF6,      ospf6,     ospf6d, 'O', 0, 1, 1,     "OSPFv3"
-ZEBRA_ROUTE_ISIS,       isis,      isisd,  'I', 1, 1, 1,     "IS-IS"
-ZEBRA_ROUTE_BGP,        bgp,       bgpd,   'B', 1, 1, 1,     "BGP"
-ZEBRA_ROUTE_PIM,       pim,       pimd,   'P', 0, 0, 0,     "PIM"
-ZEBRA_ROUTE_EIGRP,      eigrp,     eigrpd, 'E', 1, 0, 1,     "EIGRP"
-ZEBRA_ROUTE_NHRP,       nhrp,      nhrpd,  'N', 1, 1, 1,     "NHRP"
+##  type                cname      daemon  C    4  6  Redist short help       Enabled  Restrictions
+ZEBRA_ROUTE_SYSTEM,     system,    NULL,   'X', 0, 0, 0,     "Reserved",      none
+ZEBRA_ROUTE_KERNEL,     kernel,    zebra,  'K', 1, 1, 1,     "kernel route",  zebra
+ZEBRA_ROUTE_CONNECT,    connected, zebra,  'C', 1, 1, 1,     "connected",     zebra
+ZEBRA_ROUTE_STATIC,     static,    zebra,  'S', 1, 1, 1,     "static",        zebra
+ZEBRA_ROUTE_RIP,        rip,       ripd,   'R', 1, 0, 1,     "RIP",           ripd
+ZEBRA_ROUTE_RIPNG,      ripng,     ripngd, 'R', 0, 1, 1,     "RIPng",         ripngd
+ZEBRA_ROUTE_OSPF,       ospf,      ospfd,  'O', 1, 0, 1,     "OSPF",          ospfd
+ZEBRA_ROUTE_OSPF6,      ospf6,     ospf6d, 'O', 0, 1, 1,     "OSPFv3",        ospf6d
+ZEBRA_ROUTE_ISIS,       isis,      isisd,  'I', 1, 1, 1,     "IS-IS",         isisd
+ZEBRA_ROUTE_BGP,        bgp,       bgpd,   'B', 1, 1, 1,     "BGP",           bgpd
+ZEBRA_ROUTE_PIM,       pim,       pimd,   'P', 0, 0, 0,     "PIM",           pimd
+ZEBRA_ROUTE_EIGRP,      eigrp,     eigrpd, 'E', 1, 0, 1,     "EIGRP",         eigrpd
+ZEBRA_ROUTE_NHRP,       nhrp,      nhrpd,  'N', 1, 1, 1,     "NHRP",          nhrpd
 # HSLS and OLSR both are AFI independent (so: 1, 1), however
 # we want to disable for them for general Quagga distribution.
 # This at least makes it trivial for users of these protocols
 # to 'switch on' redist support (direct numeric entry remaining
 # possible).
-ZEBRA_ROUTE_HSLS,       hsls,      hslsd,  'H', 0, 0, 0,     "HSLS"
-ZEBRA_ROUTE_OLSR,       olsr,      olsrd,  'o', 0, 0, 0,     "OLSR"
-ZEBRA_ROUTE_TABLE,      table,     zebra,  'T', 1, 1, 1,     "Table"
-ZEBRA_ROUTE_LDP,        ldp,       ldpd,   'L', 0, 0, 0,     "LDP"
+ZEBRA_ROUTE_HSLS,       hsls,      hslsd,  'H', 0, 0, 0,     "HSLS",          hslsd
+ZEBRA_ROUTE_OLSR,       olsr,      olsrd,  'o', 0, 0, 0,     "OLSR",          olsrd
+ZEBRA_ROUTE_TABLE,      table,     zebra,  'T', 1, 1, 1,     "Table",         zebra
+ZEBRA_ROUTE_LDP,        ldp,       ldpd,   'L', 0, 0, 0,     "LDP",           ldpd
 #vnc when sent to zebra 
-ZEBRA_ROUTE_VNC,        vnc,       NULL,   'v', 1, 1, 1,     "VNC"
+ZEBRA_ROUTE_VNC,        vnc,       NULL,   'v', 1, 1, 1,     "VNC",           bgpd-vnc
 # vnc when sent to bgp
-ZEBRA_ROUTE_VNC_DIRECT, vnc-direct,NULL,   'V', 1, 1, 1,     "VNC-Direct", bgpd
+ZEBRA_ROUTE_VNC_DIRECT, vnc-direct,NULL,   'V', 1, 1, 1,     "VNC-Direct",    bgpd-vnc, bgpd
 # vnc when sent to bgp (resolve NVE mode)
-ZEBRA_ROUTE_VNC_DIRECT_RH, vnc-rn, NULL,   'V', 0, 0, 0,     "VNC-RN"
+ZEBRA_ROUTE_VNC_DIRECT_RH, vnc-rn, NULL,   'V', 0, 0, 0,     "VNC-RN",        bgpd-vnc
 #  bgp unicast -> vnc 
-ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL,  'b', 0, 0, 0,     "BGP-Direct"
+ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL,  'b', 0, 0, 0,     "BGP-Direct",    bgpd-vnc
 #  bgp unicast -> vnc 
-ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, 0, "BGP2VNC"
-ZEBRA_ROUTE_BABEL,      babel,     babeld, 'A', 1, 1, 1,     "Babel"
-ZEBRA_ROUTE_SHARP,      sharp,     sharpd, 'D', 1, 1, 1,     "SHARP"
-ZEBRA_ROUTE_PBR,        pbr,       pbrd,   'F', 1, 1, 0,     "PBR"
-ZEBRA_ROUTE_BFD,        bfd,       bfdd,   '-', 0, 0, 0,     "BFD"
-ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd,  'f', 1, 1, 1, "OpenFabric"
-ZEBRA_ROUTE_VRRP,       vrrp,      vrrpd,  '-', 0, 0, 0,     "VRRP"
-ZEBRA_ROUTE_NHG,        zebra,     none,  '-', 0, 0, 0,      "Nexthop Group"
-ZEBRA_ROUTE_SRTE,       srte,      none,   '-', 0, 0, 0,     "SR-TE"
-ZEBRA_ROUTE_ALL,        wildcard,  none,   '-', 0, 0, 0,     "-"
+ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, 0, "BGP2VNC", bgpd-vnc
+ZEBRA_ROUTE_BABEL,      babel,     babeld, 'A', 1, 1, 1,     "Babel",         babeld
+ZEBRA_ROUTE_SHARP,      sharp,     sharpd, 'D', 1, 1, 1,     "SHARP",         sharpd
+ZEBRA_ROUTE_PBR,        pbr,       pbrd,   'F', 1, 1, 0,     "PBR",           pbrd
+ZEBRA_ROUTE_BFD,        bfd,       bfdd,   '-', 0, 0, 0,     "BFD",           bfdd
+ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd,  'f', 1, 1, 1,  "OpenFabric",    fabricd
+ZEBRA_ROUTE_VRRP,       vrrp,      vrrpd,  '-', 0, 0, 0,     "VRRP",          vrrpd
+ZEBRA_ROUTE_NHG,        zebra,     none,   '-', 0, 0, 0,     "Nexthop Group", none
+ZEBRA_ROUTE_SRTE,       srte,      none,   '-', 0, 0, 0,     "SR-TE",         none
+ZEBRA_ROUTE_ALL,        wildcard,  none,   '-', 0, 0, 0,     "-",             none
 
 
 ## help strings
index 004beb362850b745232c5cc831ea8a991e801cdb..360fd25cc9e7b747cb1074c5c77ade5a6059609e 100644 (file)
@@ -1347,7 +1347,7 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
                                        get_route_map_delete_event(type);
                                route_map_upd8_dependency(
                                                        delete_rmap_event_type,
-                                                       rule_key,
+                                                       rule->rule_str,
                                                        index->map->name);
                        }
 
@@ -2399,6 +2399,7 @@ route_map_result_t route_map_apply(struct route_map *map,
                index = route_map_get_index(map, prefix, object,
                                            (uint8_t *)&match_ret);
                if (index) {
+                       index->applied++;
                        if (rmap_debug)
                                zlog_debug(
                                        "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
@@ -2586,22 +2587,23 @@ static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
        struct route_map_dep *dep = bucket->data;
        struct route_map_dep_data *dep_data = NULL, tmp_dep_data;
 
-       if (arg) {
-               memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
-               tmp_dep_data.rname = arg;
-               dep_data = hash_release(dep->dep_rmap_hash,
-                                       &tmp_dep_data);
-               if (dep_data) {
-                       XFREE(MTYPE_ROUTE_MAP_NAME, dep_data->rname);
-                       XFREE(MTYPE_ROUTE_MAP_DEP_DATA, dep_data);
-               }
-               if (!dep->dep_rmap_hash->count) {
-                       dep = hash_release(dep->this_hash,
-                                          (void *)dep->dep_name);
-                       hash_free(dep->dep_rmap_hash);
-                       XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
-                       XFREE(MTYPE_ROUTE_MAP_DEP, dep);
-               }
+       memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
+       tmp_dep_data.rname = arg;
+       dep_data = hash_release(dep->dep_rmap_hash, &tmp_dep_data);
+       if (dep_data) {
+               if (rmap_debug)
+                       zlog_debug("Clearing reference for %s to %s count: %d",
+                                  dep->dep_name, tmp_dep_data.rname,
+                                  dep_data->refcnt);
+
+               XFREE(MTYPE_ROUTE_MAP_NAME, dep_data->rname);
+               XFREE(MTYPE_ROUTE_MAP_DEP_DATA, dep_data);
+       }
+       if (!dep->dep_rmap_hash->count) {
+               dep = hash_release(dep->this_hash, (void *)dep->dep_name);
+               hash_free(dep->dep_rmap_hash);
+               XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
+               XFREE(MTYPE_ROUTE_MAP_DEP, dep);
        }
 }
 
@@ -2609,6 +2611,9 @@ static void route_map_clear_all_references(char *rmap_name)
 {
        int i;
 
+       if (rmap_debug)
+               zlog_debug("Clearing references for %s", rmap_name);
+
        for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
                hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
                             (void *)rmap_name);
@@ -2763,12 +2768,19 @@ static int route_map_dep_update(struct hash *dephash, const char *dep_name,
                memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
                tmp_dep_data.rname = rname;
                dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
-
-               if (!dep_data)
+               /*
+                * If dep_data is NULL then something has gone seriously
+                * wrong in route-map handling.  Note it and prevent
+                * the crash.
+                */
+               if (!dep_data) {
+                       zlog_warn(
+                               "route-map dependency for route-map %s: %s is not correct",
+                               rmap_name, dep_name);
                        goto out;
+               }
 
-               if (dep_data->refcnt)
-                       dep_data->refcnt--;
+               dep_data->refcnt--;
 
                if (!dep_data->refcnt) {
                        ret_dep_data = hash_release(dep->dep_rmap_hash,
index c9998456593bcd34b8fee12373c7e333affdbdc5..1dbf77efa4999d5110eb28a5cbadfcbb5d3ed380 100644 (file)
@@ -708,3 +708,20 @@ static ssize_t printfrr_psu(char *buf, size_t bsz, const char *fmt,
        fb.pos[0] = '\0';
        return consumed;
 }
+
+int sockunion_is_null(const union sockunion *su)
+{
+       unsigned char null_s6_addr[16] = {0};
+
+       switch (sockunion_family(su)) {
+       case AF_UNSPEC:
+               return 1;
+       case AF_INET:
+               return (su->sin.sin_addr.s_addr == 0);
+       case AF_INET6:
+               return !memcmp(su->sin6.sin6_addr.s6_addr, null_s6_addr,
+                              sizeof(null_s6_addr));
+       default:
+               return 0;
+       }
+}
index 72f12b77ca3b797710834ea95a66aa19e0e2d554..5e80ba1090b2a71b1244a564be32e257fe8d90f4 100644 (file)
@@ -102,6 +102,7 @@ extern union sockunion *sockunion_getpeername(int);
 extern union sockunion *sockunion_dup(const union sockunion *);
 extern void sockunion_free(union sockunion *);
 extern void sockunion_init(union sockunion *);
+extern int sockunion_is_null(const union sockunion *su);
 
 #ifdef _FRR_ATTRIBUTE_PRINTFRR
 #pragma FRR printfrr_ext "%pSU"  (union sockunion *)
index dc207c16a4114dc2480e4a6d476adb1625228e2c..e4e37b731572d3057efc8028385b7927617d3ccf 100644 (file)
@@ -1372,3 +1372,19 @@ void stream_fifo_free(struct stream_fifo *fifo)
        stream_fifo_deinit(fifo);
        XFREE(MTYPE_STREAM_FIFO, fifo);
 }
+
+void stream_pulldown(struct stream *s)
+{
+       size_t rlen = STREAM_READABLE(s);
+
+       /* No more data, so just move the pointers. */
+       if (rlen == 0) {
+               stream_reset(s);
+               return;
+       }
+
+       /* Move the available data to the beginning. */
+       memmove(s->data, &s->data[s->getp], rlen);
+       s->getp = 0;
+       s->endp = rlen;
+}
index 4f75f121ca25a6ad3034f51fdd800686933e256e..dedbf37984ca9023251665b87ad1f06600c03c44 100644 (file)
@@ -262,6 +262,16 @@ extern int stream_empty(struct stream *); /* is the stream empty? */
 /* debugging */
 extern void stream_hexdump(const struct stream *s);
 
+/**
+ * Reorganize the buffer data so it can fit more. This function is normally
+ * called right after stream data is consumed so we can read more data
+ * (the functions that consume data start with `stream_get*()` and macros
+ * `STREAM_GET*()`).
+ *
+ * \param s stream pointer.
+ */
+extern void stream_pulldown(struct stream *s);
+
 /* deprecated */
 extern uint8_t *stream_pnt(struct stream *);
 
index ed3c30799d9afd57eb6c65ffc3456ae4209823ba..570e0c3d287ea64af8b0e974477cd5838d5486a0 100644 (file)
@@ -26,6 +26,7 @@ lib_libfrr_la_SOURCES = \
        lib/filter_nb.c \
        lib/frrcu.c \
        lib/frrlua.c \
+       lib/frrscript.c \
        lib/frr_pthread.c \
        lib/frrstr.c \
        lib/getopt.c \
@@ -48,6 +49,7 @@ lib_libfrr_la_SOURCES = \
        lib/libfrr.c \
        lib/libfrr_trace.c \
        lib/linklist.c \
+       lib/link_state.c \
        lib/log.c \
        lib/log_filter.c \
        lib/log_vty.c \
@@ -184,6 +186,7 @@ pkginclude_HEADERS += \
        lib/filter.h \
        lib/freebsd-queue.h \
        lib/frrlua.h \
+       lib/frrscript.h \
        lib/frr_pthread.h \
        lib/frratomic.h \
        lib/frrcu.h \
@@ -208,6 +211,7 @@ pkginclude_HEADERS += \
        lib/libfrr_trace.h \
        lib/libospf.h \
        lib/linklist.h \
+       lib/link_state.h \
        lib/log.h \
        lib/log_vty.h \
        lib/md5.h \
@@ -470,8 +474,62 @@ lib/clippy-command_parse.$(OBJEXT): lib/command_lex.h
 lib/lib_clippy-command_lex.$(OBJEXT): lib/command_parse.h
 lib/lib_clippy-command_parse.$(OBJEXT): lib/command_lex.h
 
+rt_enabled =
+
+if BABELD
+rt_enabled += --enabled babeld
+endif
+if BFDD
+rt_enabled += --enabled bfdd
+endif
+if BGPD
+rt_enabled += --enabled bgpd
+if ENABLE_BGP_VNC
+rt_enabled += --enabled bgpd-vnc
+endif
+endif
+if EIGRPD
+rt_enabled += --enabled eigrpd
+endif
+if ISISD
+rt_enabled += --enabled isisd
+endif
+if FABRICD
+rt_enabled += --enabled fabricd
+endif
+if LDPD
+rt_enabled += --enabled ldpd
+endif
+if NHRPD
+rt_enabled += --enabled nhrpd
+endif
+if OSPFD
+rt_enabled += --enabled ospfd
+endif
+if OSPF6D
+rt_enabled += --enabled ospf6d
+endif
+if PBRD
+rt_enabled += --enabled pbrd
+endif
+if PIMD
+rt_enabled += --enabled pimd
+endif
+if RIPD
+rt_enabled += --enabled ripd
+endif
+if RIPNGD
+rt_enabled += --enabled ripngd
+endif
+if SHARPD
+rt_enabled += --enabled sharpd
+endif
+if ZEBRA
+rt_enabled += --enabled zebra
+endif
+
 lib/route_types.h: $(top_srcdir)/lib/route_types.txt $(top_srcdir)/lib/route_types.pl
-       $(PERL) $(top_srcdir)/lib/route_types.pl < $(top_srcdir)/lib/route_types.txt > $@
+       $(PERL) $(top_srcdir)/lib/route_types.pl $(rt_enabled) < $(top_srcdir)/lib/route_types.txt > $@
 DISTCLEANFILES += lib/route_types.h
 
 if GIT_VERSION
index e71fd74bd96f1774642a91eee95863e35b288eaf..c88605835589fa6e5d5604c0d98802b7d2cb1fbc 100644 (file)
@@ -36,6 +36,7 @@
 #include "frr_pthread.h"
 #include "lib_errors.h"
 #include "libfrr_trace.h"
+#include "libfrr.h"
 
 DEFINE_MTYPE_STATIC(LIB, THREAD, "Thread")
 DEFINE_MTYPE_STATIC(LIB, THREAD_MASTER, "Thread master")
@@ -442,8 +443,14 @@ struct thread_master *thread_master_create(const char *name)
        rv->name = XSTRDUP(MTYPE_THREAD_MASTER, name);
 
        /* Initialize I/O task data structures */
-       getrlimit(RLIMIT_NOFILE, &limit);
-       rv->fd_limit = (int)limit.rlim_cur;
+
+       /* Use configured limit if present, ulimit otherwise. */
+       rv->fd_limit = frr_get_fd_limit();
+       if (rv->fd_limit == 0) {
+               getrlimit(RLIMIT_NOFILE, &limit);
+               rv->fd_limit = (int)limit.rlim_cur;
+       }
+
        rv->read = XCALLOC(MTYPE_THREAD_POLL,
                           sizeof(struct thread *) * rv->fd_limit);
 
index fea4c490320db66631601914247da017eab81d1f..21b3d47b097b441e982861d73423a4c346425251 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -1810,7 +1810,12 @@ static int vty_accept(struct thread *thread)
        set_nonblocking(vty_sock);
        set_cloexec(vty_sock);
 
-       sockunion2hostprefix(&su, &p);
+       if (!sockunion2hostprefix(&su, &p)) {
+               close(vty_sock);
+               zlog_info("Vty unable to convert prefix from sockunion %s",
+                         sockunion2str(&su, buf, SU_ADDRSTRLEN));
+               return -1;
+       }
 
        /* VTY's accesslist apply. */
        if (p.family == AF_INET && vty_accesslist_name) {
index c59cb642f02fbd3b1d23fab2ebd04907ec54c015..383dc9f5eba634a3d28c753776008bd628197f0e 100644 (file)
@@ -92,6 +92,7 @@ static const char *const frr_native_modules[] = {
        "frr-isisd",
        "frr-vrrpd",
        "frr-zebra",
+       "frr-pathd",
 };
 /* clang-format on */
 
@@ -468,7 +469,7 @@ void yang_dnode_iterate(yang_dnode_iter_cb cb, void *arg,
                dnode = set->set.d[i];
                ret = (*cb)(dnode, arg);
                if (ret == YANG_ITER_STOP)
-                       return;
+                       break;
        }
 
        ly_set_free(set);
@@ -772,8 +773,7 @@ const struct lyd_node *yang_dnode_get_parent(const struct lyd_node *dnode,
        return NULL;
 }
 
-/* API to check if the given node is last node in the list */
-static bool yang_is_last_list_dnode(const struct lyd_node *dnode)
+bool yang_is_last_list_dnode(const struct lyd_node *dnode)
 {
        return (((dnode->next == NULL)
             || (dnode->next
@@ -785,8 +785,7 @@ static bool yang_is_last_list_dnode(const struct lyd_node *dnode)
                    != 0)));
 }
 
-/* API to check if the given node is last node in the data tree level */
-static bool yang_is_last_level_dnode(const struct lyd_node *dnode)
+bool yang_is_last_level_dnode(const struct lyd_node *dnode)
 {
        const struct lyd_node *parent;
        const struct lys_node_list *snode;
index 0cd6a4a6f236766b89471bc8ee43b68679e3db22..b8bf07ee7e167038bb76d3884d50f1362c36581d 100644 (file)
@@ -587,6 +587,11 @@ extern uint32_t yang_get_list_elements_count(const struct lyd_node *node);
 /* To get the immediate child of a dnode */
 const struct lyd_node *yang_dnode_get_child(const struct lyd_node *dnode);
 
+/* API to check if the given node is last node in the list */
+bool yang_is_last_list_dnode(const struct lyd_node *dnode);
+
+/* API to check if the given node is last node in the data tree level */
+bool yang_is_last_level_dnode(const struct lyd_node *dnode);
 
 #ifdef __cplusplus
 }
index bab1acf667a34c6278deaed6b6acdfe3e7b1bbd4..f16c94369b65c86cd882ac66ed976d7363c119cc 100644 (file)
@@ -40,6 +40,7 @@
 #include "nexthop_group.h"
 #include "lib_errors.h"
 #include "srte.h"
+#include "printfrr.h"
 
 DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
 DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
@@ -249,12 +250,12 @@ int zclient_socket_connect(struct zclient *zclient)
        return sock;
 }
 
-static int zclient_failed(struct zclient *zclient)
+static enum zclient_send_status zclient_failed(struct zclient *zclient)
 {
        zclient->fail++;
        zclient_stop(zclient);
        zclient_event(ZCLIENT_CONNECT, zclient);
-       return -1;
+       return ZCLIENT_SEND_FAILURE;
 }
 
 static int zclient_flush_data(struct thread *thread)
@@ -277,15 +278,23 @@ static int zclient_flush_data(struct thread *thread)
                                 zclient->sock, &zclient->t_write);
                break;
        case BUFFER_EMPTY:
+               if (zclient->zebra_buffer_write_ready)
+                       (*zclient->zebra_buffer_write_ready)();
                break;
        }
        return 0;
 }
 
-int zclient_send_message(struct zclient *zclient)
+/*
+ * Returns:
+ * ZCLIENT_SEND_FAILED   - is a failure
+ * ZCLIENT_SEND_SUCCESS  - means we sent data to zebra
+ * ZCLIENT_SEND_BUFFERED - means we are buffering
+ */
+enum zclient_send_status zclient_send_message(struct zclient *zclient)
 {
        if (zclient->sock < 0)
-               return -1;
+               return ZCLIENT_SEND_FAILURE;
        switch (buffer_write(zclient->wb, zclient->sock,
                             STREAM_DATA(zclient->obuf),
                             stream_get_endp(zclient->obuf))) {
@@ -296,13 +305,15 @@ int zclient_send_message(struct zclient *zclient)
                return zclient_failed(zclient);
        case BUFFER_EMPTY:
                THREAD_OFF(zclient->t_write);
-               break;
+               return ZCLIENT_SEND_SUCCESS;
        case BUFFER_PENDING:
                thread_add_write(zclient->master, zclient_flush_data, zclient,
                                 zclient->sock, &zclient->t_write);
-               break;
+               return ZCLIENT_SEND_BUFFERED;
        }
-       return 0;
+
+       /* should not get here */
+       return ZCLIENT_SEND_SUCCESS;
 }
 
 /*
@@ -362,8 +373,8 @@ stream_failure:
 }
 
 /* Send simple Zebra message. */
-static int zebra_message_send(struct zclient *zclient, int command,
-                             vrf_id_t vrf_id)
+static enum zclient_send_status zebra_message_send(struct zclient *zclient,
+                                                  int command, vrf_id_t vrf_id)
 {
        struct stream *s;
 
@@ -377,7 +388,7 @@ static int zebra_message_send(struct zclient *zclient, int command,
        return zclient_send_message(zclient);
 }
 
-int zclient_send_hello(struct zclient *zclient)
+enum zclient_send_status zclient_send_hello(struct zclient *zclient)
 {
        struct stream *s;
 
@@ -403,11 +414,13 @@ int zclient_send_hello(struct zclient *zclient)
                return zclient_send_message(zclient);
        }
 
-       return 0;
+       return ZCLIENT_SEND_SUCCESS;
 }
 
-void zclient_send_vrf_label(struct zclient *zclient, vrf_id_t vrf_id, afi_t afi,
-                           mpls_label_t label, enum lsp_types_t ltype)
+enum zclient_send_status zclient_send_vrf_label(struct zclient *zclient,
+                                               vrf_id_t vrf_id, afi_t afi,
+                                               mpls_label_t label,
+                                               enum lsp_types_t ltype)
 {
        struct stream *s;
 
@@ -419,7 +432,7 @@ void zclient_send_vrf_label(struct zclient *zclient, vrf_id_t vrf_id, afi_t afi,
        stream_putc(s, afi);
        stream_putc(s, ltype);
        stream_putw_at(s, 0, stream_get_endp(s));
-       zclient_send_message(zclient);
+       return zclient_send_message(zclient);
 }
 
 /* Send register requests to zebra daemon for the information in a VRF. */
@@ -557,9 +570,10 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id)
        }
 }
 
-int zclient_send_router_id_update(struct zclient *zclient,
-                                 zebra_message_types_t type, afi_t afi,
-                                 vrf_id_t vrf_id)
+enum zclient_send_status
+zclient_send_router_id_update(struct zclient *zclient,
+                             zebra_message_types_t type, afi_t afi,
+                             vrf_id_t vrf_id)
 {
        struct stream *s = zclient->obuf;
        stream_reset(s);
@@ -570,15 +584,16 @@ int zclient_send_router_id_update(struct zclient *zclient,
 }
 
 /* Send request to zebra daemon to start or stop RA. */
-void zclient_send_interface_radv_req(struct zclient *zclient, vrf_id_t vrf_id,
-                                    struct interface *ifp, int enable,
-                                    int ra_interval)
+enum zclient_send_status
+zclient_send_interface_radv_req(struct zclient *zclient, vrf_id_t vrf_id,
+                               struct interface *ifp, int enable,
+                               int ra_interval)
 {
        struct stream *s;
 
        /* If not connected to the zebra yet. */
        if (zclient->sock < 0)
-               return;
+               return ZCLIENT_SEND_FAILURE;
 
        /* Form and send message. */
        s = zclient->obuf;
@@ -594,16 +609,17 @@ void zclient_send_interface_radv_req(struct zclient *zclient, vrf_id_t vrf_id,
 
        stream_putw_at(s, 0, stream_get_endp(s));
 
-       zclient_send_message(zclient);
+       return zclient_send_message(zclient);
 }
 
-int zclient_send_interface_protodown(struct zclient *zclient, vrf_id_t vrf_id,
-                                    struct interface *ifp, bool down)
+enum zclient_send_status
+zclient_send_interface_protodown(struct zclient *zclient, vrf_id_t vrf_id,
+                                struct interface *ifp, bool down)
 {
        struct stream *s;
 
        if (zclient->sock < 0)
-               return -1;
+               return ZCLIENT_SEND_FAILURE;
 
        s = zclient->obuf;
        stream_reset(s);
@@ -611,9 +627,7 @@ int zclient_send_interface_protodown(struct zclient *zclient, vrf_id_t vrf_id,
        stream_putl(s, ifp->ifindex);
        stream_putc(s, !!down);
        stream_putw_at(s, 0, stream_get_endp(s));
-       zclient_send_message(zclient);
-
-       return 0;
+       return zclient_send_message(zclient);
 }
 
 /* Make connection to zebra daemon. */
@@ -712,9 +726,9 @@ static int zclient_connect(struct thread *t)
        return zclient_start(zclient);
 }
 
-int zclient_send_rnh(struct zclient *zclient, int command,
-                    const struct prefix *p, bool exact_match,
-                    vrf_id_t vrf_id)
+enum zclient_send_status zclient_send_rnh(struct zclient *zclient, int command,
+                                         const struct prefix *p,
+                                         bool exact_match, vrf_id_t vrf_id)
 {
        struct stream *s;
 
@@ -750,45 +764,10 @@ int zclient_send_rnh(struct zclient *zclient, int command,
  * The corresponding read ("xdr_decode") function on the server
  * side is zapi_route_decode().
  *
- *  0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |            Length (2)         |    Command    | Route Type    |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | ZEBRA Flags   | Message Flags | Prefix length |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Destination IPv4 Prefix for route                             |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Nexthop count |
- * +-+-+-+-+-+-+-+-+
- *
- *
- * A number of IPv4 nexthop(s) or nexthop interface index(es) are then
- * described, as per the Nexthop count. Each nexthop described as:
- *
- * +-+-+-+-+-+-+-+-+
- * | Nexthop Type  |  Set to one of ZEBRA_NEXTHOP_*
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |       IPv4 Nexthop address or Interface Index number          |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * Alternatively, if the route is a blackhole route, then Nexthop count
- * is set to 1 and a nexthop of type NEXTHOP_TYPE_BLACKHOLE is the sole
- * nexthop.
- *
- * The original struct zapi_route_*() infrastructure was built around
- * the traditional (32-bit "gate OR ifindex") nexthop data unit.
- * A special encoding can be used to feed onlink (64-bit "gate AND ifindex")
- * nexthops into zapi_route_encode() using the same zapi_route structure.
- * This is done by setting zapi_route fields as follows:
- *  - .message |= ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_ONLINK
- *  - .nexthop_num == .ifindex_num
- *  - .nexthop and .ifindex are filled with gate and ifindex parts of
- *    each compound nexthop, both in the same order
- *
  * If ZAPI_MESSAGE_DISTANCE is set, the distance value is written as a 1
  * byte value.
  *
- * If ZAPI_MESSAGE_METRIC is set, the metric value is written as an 8
+ * If ZAPI_MESSAGE_METRIC is set, the metric value is written as a 4
  * byte value.
  *
  * If ZAPI_MESSAGE_TAG is set, the tag value is written as a 4 byte value
@@ -797,11 +776,11 @@ int zclient_send_rnh(struct zclient *zclient, int command,
  *
  * XXX: No attention paid to alignment.
  */
-int zclient_route_send(uint8_t cmd, struct zclient *zclient,
-                      struct zapi_route *api)
+enum zclient_send_status
+zclient_route_send(uint8_t cmd, struct zclient *zclient, struct zapi_route *api)
 {
        if (zapi_route_encode(cmd, zclient->obuf, api) < 0)
-               return -1;
+               return ZCLIENT_SEND_FAILURE;
        return zclient_send_message(zclient);
 }
 
@@ -1058,7 +1037,8 @@ int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg)
        return 0;
 }
 
-int zclient_nhg_send(struct zclient *zclient, int cmd, struct zapi_nhg *api_nhg)
+enum zclient_send_status zclient_nhg_send(struct zclient *zclient, int cmd,
+                                         struct zapi_nhg *api_nhg)
 {
        api_nhg->proto = zclient->redist_default;
 
@@ -1203,6 +1183,12 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
        if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TABLEID))
                stream_putl(s, api->tableid);
 
+       if (CHECK_FLAG(api->message, ZAPI_MESSAGE_OPAQUE)) {
+               assert(api->opaque.length <= ZAPI_MESSAGE_OPAQUE_LENGTH);
+
+               stream_putw(s, api->opaque.length);
+               stream_write(s, api->opaque.data, api->opaque.length);
+       }
        /* Put length at the first point of the stream. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
@@ -1424,6 +1410,13 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
        if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TABLEID))
                STREAM_GETL(s, api->tableid);
 
+       if (CHECK_FLAG(api->message, ZAPI_MESSAGE_OPAQUE)) {
+               STREAM_GETW(s, api->opaque.length);
+               assert(api->opaque.length < ZAPI_MESSAGE_OPAQUE_LENGTH);
+
+               STREAM_GET(api->opaque.data, s, api->opaque.length);
+       }
+
        return 0;
 stream_failure:
        return -1;
@@ -1791,8 +1784,9 @@ stream_failure:
  * then set/unset redist[type] in the client handle (a struct zserv) for the
  * sending client
  */
-int zebra_redistribute_send(int command, struct zclient *zclient, afi_t afi,
-                           int type, unsigned short instance, vrf_id_t vrf_id)
+enum zclient_send_status
+zebra_redistribute_send(int command, struct zclient *zclient, afi_t afi,
+                       int type, unsigned short instance, vrf_id_t vrf_id)
 {
        struct stream *s;
 
@@ -1809,8 +1803,9 @@ int zebra_redistribute_send(int command, struct zclient *zclient, afi_t afi,
        return zclient_send_message(zclient);
 }
 
-int zebra_redistribute_default_send(int command, struct zclient *zclient,
-                                   afi_t afi, vrf_id_t vrf_id)
+enum zclient_send_status
+zebra_redistribute_default_send(int command, struct zclient *zclient, afi_t afi,
+                               vrf_id_t vrf_id)
 {
        struct stream *s;
 
@@ -2601,8 +2596,10 @@ stream_failure:
  * @param base Base for the label chunk. if MPLS_LABEL_BASE_ANY we do not care
  * @result 0 on success, -1 otherwise
  */
-int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
-                                uint32_t chunk_size, uint32_t base)
+enum zclient_send_status zclient_send_get_label_chunk(struct zclient *zclient,
+                                                     uint8_t keep,
+                                                     uint32_t chunk_size,
+                                                     uint32_t base)
 {
        struct stream *s;
 
@@ -2610,7 +2607,7 @@ int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
                zlog_debug("Getting Label Chunk");
 
        if (zclient->sock < 0)
-               return -1;
+               return ZCLIENT_SEND_FAILURE;
 
        s = zclient->obuf;
        stream_reset(s);
@@ -2826,7 +2823,7 @@ int tm_table_manager_connect(struct zclient *zclient)
                zlog_debug("Connecting to Table Manager");
 
        if (zclient->sock < 0)
-               return -1;
+               return ZCLIENT_SEND_FAILURE;
 
        /* send request */
        s = zclient->obuf;
@@ -2842,7 +2839,7 @@ int tm_table_manager_connect(struct zclient *zclient)
        stream_putw_at(s, 0, stream_get_endp(s));
 
        ret = zclient_send_message(zclient);
-       if (ret < 0)
+       if (ret == ZCLIENT_SEND_FAILURE)
                return -1;
 
        if (zclient_debug)
@@ -2967,14 +2964,17 @@ int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
        /* Put length at the first point of the stream. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
-       return zclient_send_message(zclient);
+       if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE)
+               return -1;
+
+       return 0;
 }
 
-int zebra_send_sr_policy(struct zclient *zclient, int cmd,
-                        struct zapi_sr_policy *zp)
+enum zclient_send_status zebra_send_sr_policy(struct zclient *zclient, int cmd,
+                                             struct zapi_sr_policy *zp)
 {
        if (zapi_sr_policy_encode(zclient->obuf, cmd, zp) < 0)
-               return -1;
+               return ZCLIENT_SEND_FAILURE;
        return zclient_send_message(zclient);
 }
 
@@ -3056,11 +3056,11 @@ stream_failure:
        return -1;
 }
 
-int zebra_send_mpls_labels(struct zclient *zclient, int cmd,
-                          struct zapi_labels *zl)
+enum zclient_send_status zebra_send_mpls_labels(struct zclient *zclient,
+                                               int cmd, struct zapi_labels *zl)
 {
        if (zapi_labels_encode(zclient->obuf, cmd, zl) < 0)
-               return -1;
+               return ZCLIENT_SEND_FAILURE;
        return zclient_send_message(zclient);
 }
 
@@ -3221,7 +3221,8 @@ stream_failure:
        return -1;
 }
 
-int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw)
+enum zclient_send_status zebra_send_pw(struct zclient *zclient, int command,
+                                      struct zapi_pw *pw)
 {
        struct stream *s;
 
@@ -3247,7 +3248,7 @@ int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw)
                break;
        default:
                flog_err(EC_LIB_ZAPI_ENCODE, "%s: unknown af", __func__);
-               return -1;
+               return ZCLIENT_SEND_FAILURE;
        }
 
        /* Put labels */
@@ -3316,7 +3317,8 @@ stream_failure:
        return;
 }
 
-void zclient_send_mlag_register(struct zclient *client, uint32_t bit_map)
+enum zclient_send_status zclient_send_mlag_register(struct zclient *client,
+                                                   uint32_t bit_map)
 {
        struct stream *s;
 
@@ -3327,15 +3329,16 @@ void zclient_send_mlag_register(struct zclient *client, uint32_t bit_map)
        stream_putl(s, bit_map);
 
        stream_putw_at(s, 0, stream_get_endp(s));
-       zclient_send_message(client);
+       return zclient_send_message(client);
 }
 
-void zclient_send_mlag_deregister(struct zclient *client)
+enum zclient_send_status zclient_send_mlag_deregister(struct zclient *client)
 {
-       zebra_message_send(client, ZEBRA_MLAG_CLIENT_UNREGISTER, VRF_DEFAULT);
+       return zebra_message_send(client, ZEBRA_MLAG_CLIENT_UNREGISTER, VRF_DEFAULT);
 }
 
-void zclient_send_mlag_data(struct zclient *client, struct stream *client_s)
+enum zclient_send_status zclient_send_mlag_data(struct zclient *client,
+                                               struct stream *client_s)
 {
        struct stream *s;
 
@@ -3346,7 +3349,7 @@ void zclient_send_mlag_data(struct zclient *client, struct stream *client_s)
        stream_put(s, client_s->data, client_s->endp);
 
        stream_putw_at(s, 0, stream_get_endp(s));
-       zclient_send_message(client);
+       return zclient_send_message(client);
 }
 
 static void zclient_mlag_process_up(ZAPI_CALLBACK_ARGS)
@@ -3371,17 +3374,17 @@ static void zclient_mlag_handle_msg(ZAPI_CALLBACK_ARGS)
  * Send an OPAQUE message, contents opaque to zebra. The message header
  * is a message subtype.
  */
-int zclient_send_opaque(struct zclient *zclient, uint32_t type,
-                       const uint8_t *data, size_t datasize)
+enum zclient_send_status zclient_send_opaque(struct zclient *zclient,
+                                            uint32_t type, const uint8_t *data,
+                                            size_t datasize)
 {
-       int ret;
        struct stream *s;
        uint16_t flags = 0;
 
        /* Check buffer size */
        if (STREAM_SIZE(zclient->obuf) <
            (ZEBRA_HEADER_SIZE + sizeof(type) + datasize))
-               return -1;
+               return ZCLIENT_SEND_FAILURE;
 
        s = zclient->obuf;
        stream_reset(s);
@@ -3398,28 +3401,26 @@ int zclient_send_opaque(struct zclient *zclient, uint32_t type,
        /* Put length into the header at the start of the stream. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
-       ret = zclient_send_message(zclient);
-
-       return ret;
+       return zclient_send_message(zclient);
 }
 
 /*
  * Send an OPAQUE message to a specific zclient. The contents are opaque
  * to zebra.
  */
-int zclient_send_opaque_unicast(struct zclient *zclient, uint32_t type,
-                               uint8_t proto, uint16_t instance,
-                               uint32_t session_id, const uint8_t *data,
-                               size_t datasize)
+enum zclient_send_status
+zclient_send_opaque_unicast(struct zclient *zclient, uint32_t type,
+                           uint8_t proto, uint16_t instance,
+                           uint32_t session_id, const uint8_t *data,
+                           size_t datasize)
 {
-       int ret;
        struct stream *s;
        uint16_t flags = 0;
 
        /* Check buffer size */
        if (STREAM_SIZE(zclient->obuf) <
            (ZEBRA_HEADER_SIZE + sizeof(struct zapi_opaque_msg) + datasize))
-               return -1;
+               return ZCLIENT_SEND_FAILURE;
 
        s = zclient->obuf;
        stream_reset(s);
@@ -3442,9 +3443,7 @@ int zclient_send_opaque_unicast(struct zclient *zclient, uint32_t type,
        /* Put length into the header at the start of the stream. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
-       ret = zclient_send_message(zclient);
-
-       return ret;
+       return zclient_send_message(zclient);
 }
 
 /*
@@ -3477,9 +3476,9 @@ stream_failure:
 /*
  * Send a registration request for opaque messages with a specified subtype.
  */
-int zclient_register_opaque(struct zclient *zclient, uint32_t type)
+enum zclient_send_status zclient_register_opaque(struct zclient *zclient,
+                                                uint32_t type)
 {
-       int ret;
        struct stream *s;
 
        s = zclient->obuf;
@@ -3498,17 +3497,15 @@ int zclient_register_opaque(struct zclient *zclient, uint32_t type)
        /* Put length at the first point of the stream. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
-       ret = zclient_send_message(zclient);
-
-       return ret;
+       return zclient_send_message(zclient);
 }
 
 /*
  * Send an un-registration request for a specified opaque subtype.
  */
-int zclient_unregister_opaque(struct zclient *zclient, uint32_t type)
+enum zclient_send_status zclient_unregister_opaque(struct zclient *zclient,
+                                                  uint32_t type)
 {
-       int ret;
        struct stream *s;
 
        s = zclient->obuf;
@@ -3527,9 +3524,7 @@ int zclient_unregister_opaque(struct zclient *zclient, uint32_t type)
        /* Put length at the first point of the stream. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
-       ret = zclient_send_message(zclient);
-
-       return ret;
+       return zclient_send_message(zclient);
 }
 
 /* Utility to decode opaque registration info */
@@ -3547,6 +3542,23 @@ stream_failure:
        return -1;
 }
 
+/* Utility to decode client close notify info */
+int zapi_client_close_notify_decode(struct stream *s,
+                                   struct zapi_client_close_info *info)
+{
+       memset(info, 0, sizeof(*info));
+
+       STREAM_GETC(s, info->proto);
+       STREAM_GETW(s, info->instance);
+       STREAM_GETL(s, info->session_id);
+
+       return 0;
+
+stream_failure:
+
+       return -1;
+}
+
 /* Zebra client message read function. */
 static int zclient_read(struct thread *thread)
 {
@@ -3887,6 +3899,12 @@ static int zclient_read(struct thread *thread)
                if (zclient->sr_policy_notify_status)
                        (*zclient->sr_policy_notify_status)(command, zclient,
                                                            length, vrf_id);
+               break;
+       case ZEBRA_CLIENT_CLOSE_NOTIFY:
+               if (zclient->zebra_client_close_notify)
+                       (*zclient->zebra_client_close_notify)(command, zclient,
+                                                             length, vrf_id);
+               break;
        default:
                break;
        }
@@ -3984,9 +4002,9 @@ static void zclient_event(enum event event, struct zclient *zclient)
        }
 }
 
-void zclient_interface_set_master(struct zclient *client,
-                                 struct interface *master,
-                                 struct interface *slave)
+enum zclient_send_status zclient_interface_set_master(struct zclient *client,
+                                                     struct interface *master,
+                                                     struct interface *slave)
 {
        struct stream *s;
 
@@ -4001,20 +4019,21 @@ void zclient_interface_set_master(struct zclient *client,
        stream_putl(s, slave->ifindex);
 
        stream_putw_at(s, 0, stream_get_endp(s));
-       zclient_send_message(client);
+       return zclient_send_message(client);
 }
 
 /*
  * Send capabilities message to zebra
  */
-int32_t zclient_capabilities_send(uint32_t cmd, struct zclient *zclient,
-                                 struct zapi_cap *api)
+enum zclient_send_status zclient_capabilities_send(uint32_t cmd,
+                                                  struct zclient *zclient,
+                                                  struct zapi_cap *api)
 {
 
        struct stream *s;
 
        if (zclient == NULL)
-               return -1;
+               return ZCLIENT_SEND_FAILURE;
 
        s = zclient->obuf;
        stream_reset(s);
@@ -4073,9 +4092,10 @@ stream_failure:
        return 0;
 }
 
-int zclient_send_neigh_discovery_req(struct zclient *zclient,
-                                    const struct interface *ifp,
-                                    const struct prefix *p)
+enum zclient_send_status
+zclient_send_neigh_discovery_req(struct zclient *zclient,
+                                const struct interface *ifp,
+                                const struct prefix *p)
 {
        struct stream *s;
 
@@ -4102,3 +4122,51 @@ uint32_t zclient_get_nhg_start(uint32_t proto)
 
        return ZEBRA_NHG_PROTO_SPACING * proto;
 }
+
+char *zclient_dump_route_flags(uint32_t flags, char *buf, size_t len)
+{
+       if (flags == 0) {
+               snprintfrr(buf, len, "None ");
+               return buf;
+       }
+
+       snprintfrr(
+               buf, len, "%s%s%s%s%s%s%s%s%s%s",
+               CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION) ? "Recursion "
+                                                             : "",
+               CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE) ? "Self " : "",
+               CHECK_FLAG(flags, ZEBRA_FLAG_IBGP) ? "iBGP " : "",
+               CHECK_FLAG(flags, ZEBRA_FLAG_SELECTED) ? "Selected " : "",
+               CHECK_FLAG(flags, ZEBRA_FLAG_FIB_OVERRIDE) ? "Override " : "",
+               CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE) ? "Evpn " : "",
+               CHECK_FLAG(flags, ZEBRA_FLAG_RR_USE_DISTANCE) ? "RR Distance "
+                                                             : "",
+               CHECK_FLAG(flags, ZEBRA_FLAG_TRAPPED) ? "Trapped " : "",
+               CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOADED) ? "Offloaded " : "",
+               CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOAD_FAILED) ? "Offload Failed "
+                                                            : "");
+       return buf;
+}
+
+char *zclient_evpn_dump_macip_flags(uint8_t flags, char *buf, size_t len)
+{
+       if (flags == 0) {
+               snprintfrr(buf, len, "None ");
+               return buf;
+       }
+
+       snprintfrr(
+               buf, len, "%s%s%s%s%s%s%s",
+               CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? "Sticky MAC " : "",
+               CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? "Gateway MAC " : "",
+               CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? "Router "
+                                                               : "",
+               CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_OVERRIDE_FLAG) ? "Override "
+                                                                 : "",
+               CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP) ? "SVI MAC " : "",
+               CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT) ? "Proxy "
+                                                                : "",
+               CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SYNC_PATH) ? "Sync " : "");
+
+       return buf;
+}
index 3c80ba7efa5a9592f8ad942d7fcb028ac8081f41..57bad7c2e6cdcef53c8cf310d2393e23f5d77e11 100644 (file)
@@ -54,6 +54,7 @@ typedef uint16_t zebra_size_t;
 
 /* For input/output buffer to zebra. */
 #define ZEBRA_MAX_PACKET_SIZ          16384U
+#define ZEBRA_SMALL_PACKET_SIZE       200U
 
 /* Zebra header size. */
 #define ZEBRA_HEADER_SIZE             10
@@ -219,6 +220,7 @@ typedef enum {
        ZEBRA_OPAQUE_UNREGISTER,
        ZEBRA_NEIGH_DISCOVER,
        ZEBRA_ROUTE_NOTIFY_REQUEST,
+       ZEBRA_CLIENT_CLOSE_NOTIFY,
 } zebra_message_types_t;
 
 enum zebra_error_types {
@@ -320,6 +322,18 @@ struct zclient {
        /* Pointer to the callback functions. */
        void (*zebra_connected)(struct zclient *);
        void (*zebra_capabilities)(struct zclient_capabilities *cap);
+
+       /*
+        * When the zclient attempts to write the stream data to
+        * it's named pipe to/from zebra, we may have a situation
+        * where the other daemon has not fully drained the data
+        * from the socket.  In this case provide a mechanism
+        * where we will *still* buffer the data to be sent
+        * and also provide a callback mechanism to the appropriate
+        * place where we can signal that we're ready to receive
+        * more data.
+        */
+       void (*zebra_buffer_write_ready)(void);
        int (*router_id_update)(ZAPI_CALLBACK_ARGS);
        int (*interface_address_add)(ZAPI_CALLBACK_ARGS);
        int (*interface_address_delete)(ZAPI_CALLBACK_ARGS);
@@ -364,6 +378,7 @@ struct zclient {
        int (*opaque_register_handler)(ZAPI_CALLBACK_ARGS);
        int (*opaque_unregister_handler)(ZAPI_CALLBACK_ARGS);
        int (*sr_policy_notify_status)(ZAPI_CALLBACK_ARGS);
+       int (*zebra_client_close_notify)(ZAPI_CALLBACK_ARGS);
 };
 
 /* Zebra API message flag. */
@@ -376,14 +391,14 @@ struct zclient {
 /* Backup nexthops are present */
 #define ZAPI_MESSAGE_BACKUP_NEXTHOPS 0x40
 #define ZAPI_MESSAGE_NHG 0x80
-
 /*
  * This should only be used by a DAEMON that needs to communicate
  * the table being used is not in the VRF.  You must pass the
  * default vrf, else this will be ignored.
  */
-#define ZAPI_MESSAGE_TABLEID 0x0080
-#define ZAPI_MESSAGE_SRTE 0x0100
+#define ZAPI_MESSAGE_TABLEID 0x0100
+#define ZAPI_MESSAGE_SRTE 0x0200
+#define ZAPI_MESSAGE_OPAQUE 0x0400
 
 #define ZSERV_VERSION 6
 /* Zserv protocol message header */
@@ -464,6 +479,7 @@ struct zapi_route {
        uint8_t type;
        unsigned short instance;
 
+       /* If you add flags, update zclient_dump_route_flags */
        uint32_t flags;
 /*
  * Cause Zebra to consider this routes nexthops recursively
@@ -557,8 +573,16 @@ struct zapi_route {
 
        /* SR-TE color (used for nexthop updates only). */
        uint32_t srte_color;
+
+#define ZAPI_MESSAGE_OPAQUE_LENGTH 1024
+       struct {
+               uint16_t length;
+               uint8_t data[ZAPI_MESSAGE_OPAQUE_LENGTH];
+       } opaque;
 };
 
+extern char *zclient_dump_route_flags(uint32_t flags, char *buf, size_t len);
+
 struct zapi_labels {
        uint8_t message;
 #define ZAPI_LABELS_FTN           0x01
@@ -613,6 +637,52 @@ struct zapi_pw_status {
        uint32_t status;
 };
 
+/* IGP instance data associated to a RLFA. */
+struct zapi_rlfa_igp {
+       vrf_id_t vrf_id;
+       int protocol;
+       union {
+               struct {
+                       char area_tag[32];
+                       struct {
+                               int tree_id;
+                               int level;
+                               unsigned int run_id;
+                       } spf;
+               } isis;
+       };
+};
+
+/* IGP -> LDP RLFA (un)registration message. */
+struct zapi_rlfa_request {
+       /* IGP instance data. */
+       struct zapi_rlfa_igp igp;
+
+       /* Destination prefix. */
+       struct prefix destination;
+
+       /* PQ node address. */
+       struct in_addr pq_address;
+};
+
+/* LDP -> IGP RLFA label update. */
+struct zapi_rlfa_response {
+       /* IGP instance data. */
+       struct zapi_rlfa_igp igp;
+
+       /* Destination prefix. */
+       struct prefix destination;
+
+       /* Resolved LDP labels. */
+       mpls_label_t pq_label;
+       uint16_t nexthop_num;
+       struct {
+               int family;
+               union g_addr gate;
+               mpls_label_t label;
+       } nexthops[MULTIPATH_NUM];
+};
+
 enum zapi_route_notify_owner {
        ZAPI_ROUTE_FAIL_INSTALL,
        ZAPI_ROUTE_BETTER_ADMIN_WON,
@@ -663,6 +733,12 @@ enum zapi_iptable_notify_owner {
        ZAPI_IPTABLE_FAIL_REMOVE,
 };
 
+enum zclient_send_status {
+       ZCLIENT_SEND_FAILURE = -1,
+       ZCLIENT_SEND_SUCCESS = 0,
+       ZCLIENT_SEND_BUFFERED = 1
+};
+
 static inline const char *
 zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note)
 {
@@ -695,8 +771,11 @@ zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note)
 #define ZEBRA_MACIP_TYPE_PROXY_ADVERT          0x20 /* Not locally active */
 #define ZEBRA_MACIP_TYPE_SYNC_PATH             0x40 /* sync path */
 /* XXX - flags is an u8; that needs to be changed to u32 if you need
- * to allocate past 0x80
+ * to allocate past 0x80.  Additionally touch zclient_evpn_dump_macip_flags
  */
+#define MACIP_BUF_SIZE 128
+extern char *zclient_evpn_dump_macip_flags(uint8_t flags, char *buf,
+                                          size_t len);
 
 /* Zebra ES VTEP flags (ZEBRA_REMOTE_ES_VTEP_ADD) */
 /* ESR has been rxed from the VTEP. Only VTEPs that have advertised the
@@ -760,31 +839,33 @@ extern void redist_del_all_instances(struct redist_proto *red);
  * we have installed and play some special games
  * to get them both installed.
  */
-extern void zclient_send_vrf_label(struct zclient *zclient, vrf_id_t vrf_id,
-                                  afi_t afi, mpls_label_t label,
-                                  enum lsp_types_t ltype);
+extern enum zclient_send_status
+zclient_send_vrf_label(struct zclient *zclient, vrf_id_t vrf_id, afi_t afi,
+                      mpls_label_t label, enum lsp_types_t ltype);
 
 extern void zclient_send_reg_requests(struct zclient *, vrf_id_t);
 extern void zclient_send_dereg_requests(struct zclient *, vrf_id_t);
-extern int zclient_send_router_id_update(struct zclient *zclient,
-                                        zebra_message_types_t type, afi_t afi,
-                                        vrf_id_t vrf_id);
-
-extern void zclient_send_interface_radv_req(struct zclient *zclient,
-                                           vrf_id_t vrf_id,
-                                           struct interface *ifp, int enable,
-                                           int ra_interval);
-extern int zclient_send_interface_protodown(struct zclient *zclient,
-                                           vrf_id_t vrf_id,
-                                           struct interface *ifp, bool down);
+extern enum zclient_send_status
+zclient_send_router_id_update(struct zclient *zclient,
+                             zebra_message_types_t type, afi_t afi,
+                             vrf_id_t vrf_id);
+
+extern enum zclient_send_status
+zclient_send_interface_radv_req(struct zclient *zclient, vrf_id_t vrf_id,
+                               struct interface *ifp, int enable,
+                               int ra_interval);
+extern enum zclient_send_status
+zclient_send_interface_protodown(struct zclient *zclient, vrf_id_t vrf_id,
+                                struct interface *ifp, bool down);
 
 /* Send redistribute command to zebra daemon. Do not update zclient state. */
-extern int zebra_redistribute_send(int command, struct zclient *, afi_t,
-                                  int type, unsigned short instance,
-                                  vrf_id_t vrf_id);
+extern enum zclient_send_status
+zebra_redistribute_send(int command, struct zclient *, afi_t, int type,
+                       unsigned short instance, vrf_id_t vrf_id);
 
-extern int zebra_redistribute_default_send(int command, struct zclient *zclient,
-                                          afi_t afi, vrf_id_t vrf_id);
+extern enum zclient_send_status
+zebra_redistribute_default_send(int command, struct zclient *zclient, afi_t afi,
+                               vrf_id_t vrf_id);
 
 /* Send route notify request to zebra */
 extern int zebra_route_notify_send(int command, struct zclient *zclient,
@@ -798,9 +879,14 @@ extern void zclient_redistribute(int command, struct zclient *, afi_t, int type,
 extern void zclient_redistribute_default(int command, struct zclient *,
                                         afi_t, vrf_id_t vrf_id);
 
-/* Send the message in zclient->obuf to the zebra daemon (or enqueue it).
-   Returns 0 for success or -1 on an I/O error. */
-extern int zclient_send_message(struct zclient *);
+/*
+ * Send the message in zclient->obuf to the zebra daemon (or enqueue it).
+ * Returns:
+ * -1 on a I/O error
+ *  0 data was successfully sent
+ *  1 data was buffered for future usage
+ */
+extern enum zclient_send_status zclient_send_message(struct zclient *);
 
 /* create header for command, length to be filled in by user later */
 extern void zclient_create_header(struct stream *, uint16_t, vrf_id_t);
@@ -857,9 +943,9 @@ extern int zclient_read_header(struct stream *s, int sock, uint16_t *size,
  */
 extern bool zapi_parse_header(struct stream *zmsg, struct zmsghdr *hdr);
 
-extern void zclient_interface_set_master(struct zclient *client,
-                                        struct interface *master,
-                                        struct interface *slave);
+extern enum zclient_send_status
+zclient_interface_set_master(struct zclient *client, struct interface *master,
+                            struct interface *slave);
 extern struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t);
 extern struct connected *zebra_interface_address_read(int, struct stream *,
                                                      vrf_id_t);
@@ -874,8 +960,9 @@ extern struct interface *zebra_interface_link_params_read(struct stream *s,
                                                          vrf_id_t vrf_id);
 extern size_t zebra_interface_link_params_write(struct stream *,
                                                struct interface *);
-extern int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
-                                       uint32_t chunk_size, uint32_t base);
+extern enum zclient_send_status
+zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
+                            uint32_t chunk_size, uint32_t base);
 
 extern int lm_label_manager_connect(struct zclient *zclient, int async);
 extern int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
@@ -889,29 +976,32 @@ extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size,
 extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
                                  uint32_t end);
 
-extern int zebra_send_sr_policy(struct zclient *zclient, int cmd,
-                               struct zapi_sr_policy *zp);
+extern enum zclient_send_status zebra_send_sr_policy(struct zclient *zclient,
+                                                    int cmd,
+                                                    struct zapi_sr_policy *zp);
 extern int zapi_sr_policy_encode(struct stream *s, int cmd,
                                 struct zapi_sr_policy *zp);
 extern int zapi_sr_policy_decode(struct stream *s, struct zapi_sr_policy *zp);
 extern int zapi_sr_policy_notify_status_decode(struct stream *s,
                                               struct zapi_sr_policy *zp);
 
-extern int zebra_send_mpls_labels(struct zclient *zclient, int cmd,
-                                 struct zapi_labels *zl);
+extern enum zclient_send_status zebra_send_mpls_labels(struct zclient *zclient,
+                                                      int cmd,
+                                                      struct zapi_labels *zl);
 extern int zapi_labels_encode(struct stream *s, int cmd,
                              struct zapi_labels *zl);
 extern int zapi_labels_decode(struct stream *s, struct zapi_labels *zl);
 
-extern int zebra_send_pw(struct zclient *zclient, int command,
-                        struct zapi_pw *pw);
+extern enum zclient_send_status zebra_send_pw(struct zclient *zclient,
+                                             int command, struct zapi_pw *pw);
 extern int zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS,
                                       struct zapi_pw_status *pw);
 
-extern int zclient_route_send(uint8_t, struct zclient *, struct zapi_route *);
-extern int zclient_send_rnh(struct zclient *zclient, int command,
-                           const struct prefix *p, bool exact_match,
-                           vrf_id_t vrf_id);
+extern enum zclient_send_status zclient_route_send(uint8_t, struct zclient *,
+                                                  struct zapi_route *);
+extern enum zclient_send_status
+zclient_send_rnh(struct zclient *zclient, int command, const struct prefix *p,
+                bool exact_match, vrf_id_t vrf_id);
 int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
                        uint32_t api_flags, uint32_t api_message);
 extern int zapi_route_encode(uint8_t, struct stream *, struct zapi_route *);
@@ -934,8 +1024,8 @@ bool zapi_ipset_notify_decode(struct stream *s,
 
 extern int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg);
 extern int zapi_nhg_decode(struct stream *s, int cmd, struct zapi_nhg *api_nhg);
-extern int zclient_nhg_send(struct zclient *zclient, int cmd,
-                           struct zapi_nhg *api_nhg);
+extern enum zclient_send_status
+zclient_nhg_send(struct zclient *zclient, int cmd, struct zapi_nhg *api_nhg);
 
 #define ZEBRA_IPSET_NAME_SIZE   32
 
@@ -962,8 +1052,9 @@ const char *zapi_nexthop2str(const struct zapi_nexthop *znh, char *buf,
 extern bool zapi_error_decode(struct stream *s, enum zebra_error_types *error);
 
 /* Encode and decode restart capabilities */
-extern int32_t zclient_capabilities_send(uint32_t cmd, struct zclient *zclient,
-                                        struct zapi_cap *api);
+extern enum zclient_send_status
+zclient_capabilities_send(uint32_t cmd, struct zclient *zclient,
+                         struct zapi_cap *api);
 extern int32_t zapi_capabilities_decode(struct stream *s, struct zapi_cap *api);
 
 static inline void zapi_route_set_blackhole(struct zapi_route *api,
@@ -976,12 +1067,13 @@ static inline void zapi_route_set_blackhole(struct zapi_route *api,
        SET_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP);
 };
 
-extern void zclient_send_mlag_register(struct zclient *client,
-                                      uint32_t bit_map);
-extern void zclient_send_mlag_deregister(struct zclient *client);
+extern enum zclient_send_status
+zclient_send_mlag_register(struct zclient *client, uint32_t bit_map);
+extern enum zclient_send_status
+zclient_send_mlag_deregister(struct zclient *client);
 
-extern void zclient_send_mlag_data(struct zclient *client,
-                                  struct stream *client_s);
+extern enum zclient_send_status zclient_send_mlag_data(struct zclient *client,
+                                                      struct stream *client_s);
 
 /*
  * Send an OPAQUE message, contents opaque to zebra - but note that
@@ -991,13 +1083,15 @@ extern void zclient_send_mlag_data(struct zclient *client,
  * below to avoid sub-type collisions. Clients use the registration
  * apis to manage the specific opaque subtypes they want to receive.
  */
-int zclient_send_opaque(struct zclient *zclient, uint32_t type,
-                       const uint8_t *data, size_t datasize);
+enum zclient_send_status zclient_send_opaque(struct zclient *zclient,
+                                            uint32_t type, const uint8_t *data,
+                                            size_t datasize);
 
-int zclient_send_opaque_unicast(struct zclient *zclient, uint32_t type,
-                               uint8_t proto, uint16_t instance,
-                               uint32_t session_id, const uint8_t *data,
-                               size_t datasize);
+enum zclient_send_status
+zclient_send_opaque_unicast(struct zclient *zclient, uint32_t type,
+                           uint8_t proto, uint16_t instance,
+                           uint32_t session_id, const uint8_t *data,
+                           size_t datasize);
 
 /* Struct representing the decoded opaque header info */
 struct zapi_opaque_msg {
@@ -1027,8 +1121,10 @@ struct zapi_opaque_reg_info {
 /* Decode incoming opaque */
 int zclient_opaque_decode(struct stream *msg, struct zapi_opaque_msg *info);
 
-int zclient_register_opaque(struct zclient *zclient, uint32_t type);
-int zclient_unregister_opaque(struct zclient *zclient, uint32_t type);
+enum zclient_send_status zclient_register_opaque(struct zclient *zclient,
+                                                uint32_t type);
+enum zclient_send_status zclient_unregister_opaque(struct zclient *zclient,
+                                                  uint32_t type);
 int zapi_opaque_reg_decode(struct stream *msg,
                           struct zapi_opaque_reg_info *info);
 
@@ -1047,18 +1143,34 @@ enum zapi_opaque_registry {
        LDP_IGP_SYNC_IF_STATE_UPDATE = 4,
        /* Announce that LDP is up  */
        LDP_IGP_SYNC_ANNOUNCE_UPDATE = 5,
-       /* Heartbeat indicating that LDP is running */
-       LDP_IGP_SYNC_HELLO_UPDATE = 6,
+       /* Register RLFA with LDP */
+       LDP_RLFA_REGISTER = 7,
+       /* Unregister all RLFAs with LDP */
+       LDP_RLFA_UNREGISTER_ALL = 8,
+       /* Announce LDP labels associated to a previously registered RLFA */
+       LDP_RLFA_LABELS = 9,
 };
 
 /* Send the hello message.
  * Returns 0 for success or -1 on an I/O error.
  */
-extern int zclient_send_hello(struct zclient *client);
+extern enum zclient_send_status zclient_send_hello(struct zclient *client);
+
+extern enum zclient_send_status
+zclient_send_neigh_discovery_req(struct zclient *zclient,
+                                const struct interface *ifp,
+                                const struct prefix *p);
+
+struct zapi_client_close_info {
+       /* Client session tuple */
+       uint8_t proto;
+       uint16_t instance;
+       uint32_t session_id;
+};
 
-extern int zclient_send_neigh_discovery_req(struct zclient *zclient,
-                                           const struct interface *ifp,
-                                           const struct prefix *p);
+/* Decode incoming client close notify */
+extern int zapi_client_close_notify_decode(struct stream *s,
+                                          struct zapi_client_close_info *info);
 
 #ifdef __cplusplus
 }
index 5831316f1f7f7258c618fd978e34b22471a446b6..067ff9838c9b2638780be6593a438176b80bab29 100644 (file)
@@ -32,6 +32,7 @@ This list tries to collect them to one source of information:
     commit "ipv4: introduce ip_dst_mtu_maybe_forward and protect forwarding path against pmtu spoofing"
   Workaround:
     Set sysctl net.ipv4.ip_forward_use_pmtu=1
+    See: https://marc.info/?t=143636239500003&r=1&w=2 for details
     (Should fix kernel to have this by default on for tunnel devices)
 
 - subtle path mtu mishandling issues
index 42f6a88f952d86bab2e5fbf7049deb949c836155..0b5a0427e6d2c251be816d60a78c18fb1a173f5a 100644 (file)
@@ -16,6 +16,7 @@
 #include "netlink.h"
 
 DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE, "NHRP cache entry")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE_CONFIG, "NHRP cache config entry")
 
 unsigned long nhrp_cache_counts[NHRP_CACHE_NUM_TYPES];
 
@@ -68,15 +69,113 @@ static void nhrp_cache_free(struct nhrp_cache *c)
 {
        struct nhrp_interface *nifp = c->ifp->info;
 
-       zassert(c->cur.type == NHRP_CACHE_INVALID && c->cur.peer == NULL);
-       zassert(c->new.type == NHRP_CACHE_INVALID && c->new.peer == NULL);
+       debugf(NHRP_DEBUG_COMMON, "Deleting cache entry");
        nhrp_cache_counts[c->cur.type]--;
        notifier_call(&c->notifier_list, NOTIFY_CACHE_DELETE);
        zassert(!notifier_active(&c->notifier_list));
        hash_release(nifp->cache_hash, c);
+       THREAD_OFF(c->t_timeout);
+       THREAD_OFF(c->t_auth);
        XFREE(MTYPE_NHRP_CACHE, c);
 }
 
+static unsigned int nhrp_cache_config_protocol_key(const void *peer_data)
+{
+       const struct nhrp_cache_config *p = peer_data;
+       return sockunion_hash(&p->remote_addr);
+}
+
+static bool nhrp_cache_config_protocol_cmp(const void *cache_data,
+                                          const void *key_data)
+{
+       const struct nhrp_cache_config *a = cache_data;
+       const struct nhrp_cache_config *b = key_data;
+
+       if (!sockunion_same(&a->remote_addr, &b->remote_addr))
+               return false;
+       if (a->ifp != b->ifp)
+               return false;
+       return true;
+}
+
+static void *nhrp_cache_config_alloc(void *data)
+{
+       struct nhrp_cache_config *p, *key = data;
+
+       p = XCALLOC(MTYPE_NHRP_CACHE_CONFIG, sizeof(struct nhrp_cache_config));
+
+       *p = (struct nhrp_cache_config){
+               .remote_addr = key->remote_addr,
+               .ifp = key->ifp,
+       };
+       return p;
+}
+
+void nhrp_cache_config_free(struct nhrp_cache_config *c)
+{
+       struct nhrp_interface *nifp = c->ifp->info;
+
+       hash_release(nifp->cache_config_hash, c);
+       XFREE(MTYPE_NHRP_CACHE_CONFIG, c);
+}
+
+struct nhrp_cache_config *nhrp_cache_config_get(struct interface *ifp,
+                                               union sockunion *remote_addr,
+                                               int create)
+{
+       struct nhrp_interface *nifp = ifp->info;
+       struct nhrp_cache_config key;
+
+       if (!nifp->cache_config_hash) {
+               nifp->cache_config_hash =
+                       hash_create(nhrp_cache_config_protocol_key,
+                                   nhrp_cache_config_protocol_cmp,
+                                   "NHRP Config Cache");
+               if (!nifp->cache_config_hash)
+                       return NULL;
+       }
+       key.remote_addr = *remote_addr;
+       key.ifp = ifp;
+
+       return hash_get(nifp->cache_config_hash, &key,
+                       create ? nhrp_cache_config_alloc : NULL);
+}
+
+static void do_nhrp_cache_free(struct hash_bucket *hb,
+                              void *arg __attribute__((__unused__)))
+{
+       struct nhrp_cache *c = hb->data;
+
+       nhrp_cache_free(c);
+}
+
+static void do_nhrp_cache_config_free(struct hash_bucket *hb,
+                                     void *arg __attribute__((__unused__)))
+{
+       struct nhrp_cache_config *cc = hb->data;
+
+       nhrp_cache_config_free(cc);
+}
+
+void nhrp_cache_interface_del(struct interface *ifp)
+{
+       struct nhrp_interface *nifp = ifp->info;
+
+       debugf(NHRP_DEBUG_COMMON, "Cleaning up undeleted cache entries (%lu)",
+              nifp->cache_hash ? nifp->cache_hash->count : 0);
+
+       if (nifp->cache_hash) {
+               hash_iterate(nifp->cache_hash, do_nhrp_cache_free, NULL);
+               hash_free(nifp->cache_hash);
+       }
+
+       if (nifp->cache_config_hash) {
+               hash_iterate(nifp->cache_config_hash, do_nhrp_cache_config_free,
+                            NULL);
+               hash_free(nifp->cache_config_hash);
+       }
+}
+
 struct nhrp_cache *nhrp_cache_get(struct interface *ifp,
                                  union sockunion *remote_addr, int create)
 {
@@ -101,6 +200,7 @@ struct nhrp_cache *nhrp_cache_get(struct interface *ifp,
 static int nhrp_cache_do_free(struct thread *t)
 {
        struct nhrp_cache *c = THREAD_ARG(t);
+
        c->t_timeout = NULL;
        nhrp_cache_free(c);
        return 0;
@@ -109,6 +209,7 @@ static int nhrp_cache_do_free(struct thread *t)
 static int nhrp_cache_do_timeout(struct thread *t)
 {
        struct nhrp_cache *c = THREAD_ARG(t);
+
        c->t_timeout = NULL;
        if (c->cur.type != NHRP_CACHE_INVALID)
                nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL);
@@ -122,7 +223,8 @@ static void nhrp_cache_update_route(struct nhrp_cache *c)
        char buf[3][SU_ADDRSTRLEN];
        struct nhrp_interface *nifp;
 
-       sockunion2hostprefix(&c->remote_addr, &pfx);
+       if (!sockunion2hostprefix(&c->remote_addr, &pfx))
+               return;
 
        if (p && nhrp_peer_check(p, 1)) {
                if (sockunion_family(&c->cur.remote_nbma_natoa) != AF_UNSPEC) {
@@ -186,7 +288,7 @@ static void nhrp_cache_update_route(struct nhrp_cache *c)
                        c->nhrp_route_installed = 0;
                }
                if (c->route_installed) {
-                       sockunion2hostprefix(&c->remote_addr, &pfx);
+                       assert(sockunion2hostprefix(&c->remote_addr, &pfx));
                        notifier_call(&c->notifier_list, NOTIFY_CACHE_DOWN);
                        nhrp_route_announce(0, c->cur.type, &pfx, NULL, NULL,
                                            0);
@@ -423,12 +525,23 @@ struct nhrp_cache_iterator_ctx {
        void *ctx;
 };
 
+struct nhrp_cache_config_iterator_ctx {
+       void (*cb)(struct nhrp_cache_config *, void *);
+       void *ctx;
+};
+
 static void nhrp_cache_iterator(struct hash_bucket *b, void *ctx)
 {
        struct nhrp_cache_iterator_ctx *ic = ctx;
        ic->cb(b->data, ic->ctx);
 }
 
+static void nhrp_cache_config_iterator(struct hash_bucket *b, void *ctx)
+{
+       struct nhrp_cache_config_iterator_ctx *ic = ctx;
+       ic->cb(b->data, ic->ctx);
+}
+
 void nhrp_cache_foreach(struct interface *ifp,
                        void (*cb)(struct nhrp_cache *, void *), void *ctx)
 {
@@ -441,6 +554,18 @@ void nhrp_cache_foreach(struct interface *ifp,
                hash_iterate(nifp->cache_hash, nhrp_cache_iterator, &ic);
 }
 
+void nhrp_cache_config_foreach(struct interface *ifp,
+                              void (*cb)(struct nhrp_cache_config *, void *), void *ctx)
+{
+       struct nhrp_interface *nifp = ifp->info;
+       struct nhrp_cache_config_iterator_ctx ic = {
+               .cb = cb, .ctx = ctx,
+       };
+
+       if (nifp->cache_config_hash)
+               hash_iterate(nifp->cache_config_hash, nhrp_cache_config_iterator, &ic);
+}
+
 void nhrp_cache_notify_add(struct nhrp_cache *c, struct notifier_block *n,
                           notifier_fn_t fn)
 {
index 0ed2371eb0496402a1804a10b7292c841672ec6b..269499cc594710375732545852afc0f751beadcf 100644 (file)
 
 DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF, "NHRP interface")
 
+static void nhrp_interface_update_cache_config(struct interface *ifp,
+                                              bool available,
+                                              uint8_t family);
+
 static int nhrp_if_new_hook(struct interface *ifp)
 {
        struct nhrp_interface *nifp;
@@ -45,6 +49,21 @@ static int nhrp_if_new_hook(struct interface *ifp)
 
 static int nhrp_if_delete_hook(struct interface *ifp)
 {
+       struct nhrp_interface *nifp = ifp->info;
+
+       debugf(NHRP_DEBUG_IF, "Deleted interface (%s)", ifp->name);
+
+       nhrp_cache_interface_del(ifp);
+       nhrp_nhs_interface_del(ifp);
+       nhrp_peer_interface_del(ifp);
+
+       if (nifp->ipsec_profile)
+               free(nifp->ipsec_profile);
+       if (nifp->ipsec_fallback_profile)
+               free(nifp->ipsec_fallback_profile);
+       if (nifp->source)
+               free(nifp->source);
+
        XFREE(MTYPE_NHRP_IF, ifp->info);
        return 0;
 }
@@ -311,11 +330,74 @@ int nhrp_ifp_destroy(struct interface *ifp)
 {
        debugf(NHRP_DEBUG_IF, "if-delete: %s", ifp->name);
 
+       nhrp_interface_update_cache_config(ifp, false, AF_INET);
+       nhrp_interface_update_cache_config(ifp, false, AF_INET6);
        nhrp_interface_update(ifp);
 
        return 0;
 }
 
+struct map_ctx {
+       int family;
+       bool enabled;
+};
+
+static void interface_config_update_nhrp_map(struct nhrp_cache_config *cc,
+                                            void *data)
+{
+       struct map_ctx *ctx = data;
+       struct interface *ifp = cc->ifp;
+       struct nhrp_cache *c;
+       union sockunion nbma_addr;
+
+       if (sockunion_family(&cc->remote_addr) != ctx->family)
+               return;
+
+       /* gre layer not ready */
+       if (ifp->vrf_id == VRF_UNKNOWN)
+               return;
+
+       c = nhrp_cache_get(ifp, &cc->remote_addr, ctx->enabled ? 1 : 0);
+       if (!c && !ctx->enabled)
+               return;
+
+       /* suppress */
+       if (!ctx->enabled) {
+               if (c && c->map) {
+                       nhrp_cache_update_binding(
+                               c, c->cur.type, -1,
+                               nhrp_peer_get(ifp, &nbma_addr), 0, NULL);
+               }
+               return;
+       }
+
+       /* Newly created */
+       assert(c != NULL);
+
+       c->map = 1;
+       if (cc->type == NHRP_CACHE_LOCAL)
+               nhrp_cache_update_binding(c, NHRP_CACHE_LOCAL, 0, NULL, 0,
+                                         NULL);
+       else {
+               nhrp_cache_update_binding(c, NHRP_CACHE_STATIC, 0,
+                                         nhrp_peer_get(ifp, &cc->nbma), 0,
+                                         NULL);
+       }
+}
+
+static void nhrp_interface_update_cache_config(struct interface *ifp, bool available, uint8_t family)
+{
+       struct map_ctx mapctx;
+
+       mapctx = (struct map_ctx){
+               .family = family,
+               .enabled = available
+       };
+       nhrp_cache_config_foreach(ifp, interface_config_update_nhrp_map,
+                                 &mapctx);
+
+}
+
 int nhrp_ifp_up(struct interface *ifp)
 {
        debugf(NHRP_DEBUG_IF, "if-up: %s", ifp->name);
@@ -345,7 +427,7 @@ int nhrp_interface_address_add(ZAPI_CALLBACK_ARGS)
 
        nhrp_interface_update_address(
                ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0);
-
+       nhrp_interface_update_cache_config(ifc->ifp, true, PREFIX_FAMILY(ifc->address));
        return 0;
 }
 
index 085cab347f722e179477c8a205cb87eb44ea84ec..540708f1aedc6e645ba0cc5ece3a70d831ea3fb9 100644 (file)
@@ -35,6 +35,7 @@ static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg)
        union sockunion cie_nbma, cie_proto, *proto;
        char buf[64];
        int ok = 0, holdtime;
+       unsigned short mtu = 0;
 
        nhrp_reqid_free(&nhrp_packet_reqid, &r->reqid);
 
@@ -57,6 +58,8 @@ static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg)
                      || (cie->code == NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
                          && nhs->hub)))
                        ok = 0;
+               mtu = ntohs(cie->mtu);
+               debugf(NHRP_DEBUG_COMMON, "NHS: CIE MTU: %d", mtu);
        }
 
        if (!ok)
@@ -96,7 +99,7 @@ static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg)
        c = nhrp_cache_get(ifp, &p->dst_proto, 1);
        if (c)
                nhrp_cache_update_binding(c, NHRP_CACHE_NHS, holdtime,
-                                         nhrp_peer_ref(r->peer), 0, NULL);
+                                         nhrp_peer_ref(r->peer), mtu, NULL);
 }
 
 static int nhrp_reg_timeout(struct thread *t)
@@ -197,7 +200,8 @@ static int nhrp_reg_send_req(struct thread *t)
 
        /* FIXME: push CIE for each local protocol address */
        cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, NULL, NULL);
-       cie->prefix_length = 0xff;
+       /* RFC2332 5.2.1 if unique is set then prefix length must be 0xff */
+       cie->prefix_length = (if_ad->flags & NHRP_IFF_REG_NO_UNIQUE) ? 8 * sockunion_get_addrlen(dst_proto) : 0xff;
        cie->holding_time = htons(if_ad->holdtime);
        cie->mtu = htons(if_ad->mtu);
 
@@ -378,6 +382,24 @@ int nhrp_nhs_free(struct nhrp_nhs *nhs)
        return 0;
 }
 
+void nhrp_nhs_interface_del(struct interface *ifp)
+{
+       struct nhrp_interface *nifp = ifp->info;
+       struct nhrp_nhs *nhs, *tmp;
+       afi_t afi;
+
+       for (afi = 0; afi < AFI_MAX; afi++) {
+               debugf(NHRP_DEBUG_COMMON, "Cleaning up nhs entries (%d)",
+                      !list_empty(&nifp->afi[afi].nhslist_head));
+
+               list_for_each_entry_safe(nhs, tmp, &nifp->afi[afi].nhslist_head,
+                                        nhslist_entry)
+               {
+                       nhrp_nhs_free(nhs);
+               }
+       }
+}
+
 void nhrp_nhs_terminate(void)
 {
        struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
index 2dc019ce65b698433bb708d665f53e883725908b..9aaa9dec1eed6930d3d0cb9d7ab122d1b227a648 100644 (file)
@@ -38,11 +38,17 @@ static void nhrp_packet_debug(struct zbuf *zb, const char *dir);
 
 static void nhrp_peer_check_delete(struct nhrp_peer *p)
 {
+       char buf[2][256];
        struct nhrp_interface *nifp = p->ifp->info;
 
        if (p->ref || notifier_active(&p->notifier_list))
                return;
 
+       debugf(NHRP_DEBUG_COMMON, "Deleting peer ref:%d remote:%s local:%s",
+              p->ref,
+              sockunion2str(&p->vc->remote.nbma, buf[0], sizeof(buf[0])),
+              sockunion2str(&p->vc->local.nbma, buf[1], sizeof(buf[1])));
+
        THREAD_OFF(p->t_fallback);
        hash_release(nifp->peer_hash, p);
        nhrp_interface_notify_del(p->ifp, &p->ifp_notifier);
@@ -185,6 +191,27 @@ static void *nhrp_peer_create(void *data)
        return p;
 }
 
+static void do_peer_hash_free(struct hash_bucket *hb,
+                             void *arg __attribute__((__unused__)))
+{
+       struct nhrp_peer *p = hb->data;
+       nhrp_peer_check_delete(p);
+}
+
+void nhrp_peer_interface_del(struct interface *ifp)
+{
+       struct nhrp_interface *nifp = ifp->info;
+
+       debugf(NHRP_DEBUG_COMMON, "Cleaning up undeleted peer entries (%lu)",
+              nifp->peer_hash ? nifp->peer_hash->count : 0);
+
+       if (nifp->peer_hash) {
+               hash_iterate(nifp->peer_hash, do_peer_hash_free, NULL);
+               assert(nifp->peer_hash->count == 0);
+               hash_free(nifp->peer_hash);
+       }
+}
+
 struct nhrp_peer *nhrp_peer_get(struct interface *ifp,
                                const union sockunion *remote_nbma)
 {
@@ -271,6 +298,8 @@ int nhrp_peer_check(struct nhrp_peer *p, int establish)
                return 0;
        if (sockunion_family(&vc->local.nbma) == AF_UNSPEC)
                return 0;
+       if (vc->ipsec)
+               return 1;
 
        p->prio = establish > 1;
        p->requested = 1;
index e7d35b90ff05e12870d54afa29747e9047a55adf..ce2b1fe2ffe7182fd5941fb929366b3e471d6632 100644 (file)
@@ -56,7 +56,7 @@ static void nhrp_route_update_put(struct route_node *rn)
        struct route_info *ri = rn->info;
 
        if (!ri->ifp && !ri->nhrp_ifp
-           && sockunion_family(&ri->via) == AF_UNSPEC) {
+           && sockunion_is_null(&ri->via)) {
                XFREE(MTYPE_NHRP_ROUTE, rn->info);
                route_unlock_node(rn);
        }
@@ -70,8 +70,7 @@ static void nhrp_route_update_zebra(const struct prefix *p,
        struct route_node *rn;
        struct route_info *ri;
 
-       rn = nhrp_route_update_get(
-               p, (sockunion_family(nexthop) != AF_UNSPEC) || ifp);
+       rn = nhrp_route_update_get(p, !sockunion_is_null(nexthop) || ifp);
        if (rn) {
                ri = rn->info;
                ri->via = *nexthop;
@@ -225,7 +224,7 @@ int nhrp_route_read(ZAPI_CALLBACK_ARGS)
               sockunion2str(&nexthop_addr, buf, sizeof(buf)),
               ifp ? ifp->name : "(none)");
 
-       nhrp_route_update_zebra(&api.prefix, &nexthop_addr, ifp);
+       nhrp_route_update_zebra(&api.prefix, &nexthop_addr, added ? ifp : NULL);
        nhrp_shortcut_prefix_change(&api.prefix, !added);
 
        return 0;
index 9a6f77334f1868e79e4d774691452468a9035c3a..6ad0c9ea03926f8a278c863f73fac3e1353e36a1 100644 (file)
@@ -62,7 +62,7 @@ static void nhrp_shortcut_cache_notify(struct notifier_block *n,
                               s->p, s->cache->ifp->name);
 
                        nhrp_route_announce(1, s->type, s->p, s->cache->ifp,
-                                           NULL, 0);
+                                           &s->cache->remote_addr, 0);
                        s->route_installed = 1;
                }
                break;
@@ -207,6 +207,7 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid,
        struct nhrp_extension_header *ext;
        struct nhrp_cie_header *cie;
        struct nhrp_cache *c = NULL;
+       struct nhrp_cache *c_dst_proto = NULL;
        union sockunion *proto, cie_proto, *nbma, cie_nbma, nat_nbma;
        struct prefix prefix, route_prefix;
        struct zbuf extpl;
@@ -304,6 +305,22 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid,
                        debugf(NHRP_DEBUG_COMMON,
                               "Shortcut: no cache for nbma %s", buf[2]);
                }
+
+               /* Update cache binding for dst_proto as well */
+               if (proto != &pp->dst_proto) {
+                       c_dst_proto = nhrp_cache_get(pp->ifp, &pp->dst_proto, 1);
+                       if (c_dst_proto) {
+                               debugf(NHRP_DEBUG_COMMON,
+                              "Shortcut: cache found, update binding");
+                               nhrp_cache_update_binding(c_dst_proto, NHRP_CACHE_DYNAMIC,
+                                                 holding_time,
+                                                 nhrp_peer_get(pp->ifp, nbma),
+                                                 htons(cie->mtu), nbma);
+                       } else {
+                               debugf(NHRP_DEBUG_COMMON,
+                              "Shortcut: no cache for nbma %s", buf[2]);
+                       }
+               }
        }
 
        /* Update shortcut entry for subnet to protocol gw binding */
@@ -397,7 +414,9 @@ void nhrp_shortcut_initiate(union sockunion *addr)
        struct prefix p;
        struct nhrp_shortcut *s;
 
-       sockunion2hostprefix(addr, &p);
+       if (!sockunion2hostprefix(addr, &p))
+               return;
+
        s = nhrp_shortcut_get(&p);
        if (s && s->type != NHRP_CACHE_INCOMPLETE) {
                s->addr = *addr;
index 27b7bece485d3ae2029221d0415bd0eb675874ca..1ea4c5e64f126924b1f44edbb09a5c323c7f1a70 100644 (file)
@@ -494,28 +494,42 @@ DEFUN(if_nhrp_map, if_nhrp_map_cmd,
        VTY_DECLVAR_CONTEXT(interface, ifp);
        afi_t afi = cmd_to_afi(argv[0]);
        union sockunion proto_addr, nbma_addr;
+       struct nhrp_cache_config *cc;
        struct nhrp_cache *c;
+       enum nhrp_cache_type type;
 
        if (str2sockunion(argv[3]->arg, &proto_addr) < 0
            || afi2family(afi) != sockunion_family(&proto_addr))
                return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH);
 
+       if (strmatch(argv[4]->text, "local"))
+               type = NHRP_CACHE_LOCAL;
+       else {
+               if (str2sockunion(argv[4]->arg, &nbma_addr) < 0)
+                       return nhrp_vty_return(vty, NHRP_ERR_FAIL);
+               type = NHRP_CACHE_STATIC;
+       }
+       cc = nhrp_cache_config_get(ifp, &proto_addr, 1);
+       if (!cc)
+               return nhrp_vty_return(vty, NHRP_ERR_FAIL);
+       cc->nbma = nbma_addr;
+       cc->type = type;
+       /* gre layer not ready */
+       if (ifp->ifindex == IFINDEX_INTERNAL)
+               return CMD_SUCCESS;
+
        c = nhrp_cache_get(ifp, &proto_addr, 1);
        if (!c)
                return nhrp_vty_return(vty, NHRP_ERR_FAIL);
 
        c->map = 1;
-       if (strmatch(argv[4]->text, "local")) {
+       if (type == NHRP_CACHE_LOCAL)
                nhrp_cache_update_binding(c, NHRP_CACHE_LOCAL, 0, NULL, 0,
                                          NULL);
-       } else {
-               if (str2sockunion(argv[4]->arg, &nbma_addr) < 0)
-                       return nhrp_vty_return(vty, NHRP_ERR_FAIL);
+       else
                nhrp_cache_update_binding(c, NHRP_CACHE_STATIC, 0,
                                          nhrp_peer_get(ifp, &nbma_addr), 0,
                                          NULL);
-       }
-
        return CMD_SUCCESS;
 }
 
@@ -533,15 +547,22 @@ DEFUN(if_no_nhrp_map, if_no_nhrp_map_cmd,
        VTY_DECLVAR_CONTEXT(interface, ifp);
        afi_t afi = cmd_to_afi(argv[1]);
        union sockunion proto_addr, nbma_addr;
+       struct nhrp_cache_config *cc;
        struct nhrp_cache *c;
 
        if (str2sockunion(argv[4]->arg, &proto_addr) < 0
            || afi2family(afi) != sockunion_family(&proto_addr))
                return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH);
 
+       cc = nhrp_cache_config_get(ifp, &proto_addr, 0);
+       if (!cc)
+               return nhrp_vty_return(vty, NHRP_ERR_FAIL);
+       nhrp_cache_config_free(cc);
+
        c = nhrp_cache_get(ifp, &proto_addr, 0);
+       /* silently return */
        if (!c || !c->map)
-               return nhrp_vty_return(vty, NHRP_ERR_ENTRY_NOT_FOUND);
+               return CMD_SUCCESS;
 
        nhrp_cache_update_binding(c, c->cur.type, -1,
                                  nhrp_peer_get(ifp, &nbma_addr), 0, NULL);
@@ -997,23 +1018,19 @@ struct write_map_ctx {
        const char *aficmd;
 };
 
-static void interface_config_write_nhrp_map(struct nhrp_cache *c, void *data)
+static void interface_config_write_nhrp_map(struct nhrp_cache_config *c, void *data)
 {
        struct write_map_ctx *ctx = data;
        struct vty *vty = ctx->vty;
        char buf[2][SU_ADDRSTRLEN];
 
-       if (!c->map)
-               return;
        if (sockunion_family(&c->remote_addr) != ctx->family)
                return;
 
        vty_out(vty, " %s nhrp map %s %s\n", ctx->aficmd,
                sockunion2str(&c->remote_addr, buf[0], sizeof(buf[0])),
-               c->cur.type == NHRP_CACHE_LOCAL
-                       ? "local"
-                       : sockunion2str(&c->cur.peer->vc->remote.nbma, buf[1],
-                                       sizeof(buf[1])));
+               c->type == NHRP_CACHE_LOCAL
+               ? "local" : sockunion2str(&c->nbma, buf[1], sizeof(buf[1])));
 }
 
 static int interface_config_write(struct vty *vty)
@@ -1076,8 +1093,8 @@ static int interface_config_write(struct vty *vty)
                                .family = afi2family(afi),
                                .aficmd = aficmd,
                        };
-                       nhrp_cache_foreach(ifp, interface_config_write_nhrp_map,
-                                          &mapctx);
+                       nhrp_cache_config_foreach(ifp, interface_config_write_nhrp_map,
+                                                 &mapctx);
 
                        list_for_each_entry(nhs, &ad->nhslist_head,
                                            nhslist_entry)
index cbee5951f30075c77d86b68aba1985999721952d..a36d0c445db8412c215577f92383a03063cdcb86 100644 (file)
@@ -124,7 +124,7 @@ enum nhrp_notify_type {
 
 struct nhrp_vc {
        struct notifier_list notifier_list;
-       uint8_t ipsec;
+       uint32_t ipsec;
        uint8_t updating;
        uint8_t abort_migration;
 
@@ -197,6 +197,13 @@ enum nhrp_cache_type {
 extern const char *const nhrp_cache_type_str[];
 extern unsigned long nhrp_cache_counts[NHRP_CACHE_NUM_TYPES];
 
+struct nhrp_cache_config {
+       struct interface *ifp;
+       union sockunion remote_addr;
+       enum nhrp_cache_type type;
+       union sockunion nbma;
+};
+
 struct nhrp_cache {
        struct interface *ifp;
        union sockunion remote_addr;
@@ -280,6 +287,7 @@ struct nhrp_interface {
        uint32_t grekey;
 
        struct hash *peer_hash;
+       struct hash *cache_config_hash;
        struct hash *cache_hash;
 
        struct notifier_list notifier_list;
@@ -335,6 +343,7 @@ void nhrp_nhs_foreach(struct interface *ifp, afi_t afi,
                      void (*cb)(struct nhrp_nhs *, struct nhrp_registration *,
                                 void *),
                      void *ctx);
+void nhrp_nhs_interface_del(struct interface *ifp);
 
 void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp);
 void nhrp_route_announce(int add, enum nhrp_cache_type type,
@@ -358,10 +367,17 @@ void nhrp_shortcut_foreach(afi_t afi,
 void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force);
 void nhrp_shortcut_prefix_change(const struct prefix *p, int deleted);
 
+void nhrp_cache_interface_del(struct interface *ifp);
+void nhrp_cache_config_free(struct nhrp_cache_config *c);
+struct nhrp_cache_config *nhrp_cache_config_get(struct interface *ifp,
+                                               union sockunion *remote_addr,
+                                               int create);
 struct nhrp_cache *nhrp_cache_get(struct interface *ifp,
                                  union sockunion *remote_addr, int create);
 void nhrp_cache_foreach(struct interface *ifp,
                        void (*cb)(struct nhrp_cache *, void *), void *ctx);
+void nhrp_cache_config_foreach(struct interface *ifp,
+                              void (*cb)(struct nhrp_cache_config *, void *), void *ctx);
 void nhrp_cache_set_used(struct nhrp_cache *, int);
 int nhrp_cache_update_binding(struct nhrp_cache *, enum nhrp_cache_type type,
                              int holding_time, struct nhrp_peer *p,
@@ -432,6 +448,7 @@ struct nhrp_reqid *nhrp_reqid_lookup(struct nhrp_reqid_pool *, uint32_t reqid);
 
 int nhrp_packet_init(void);
 
+void nhrp_peer_interface_del(struct interface *ifp);
 struct nhrp_peer *nhrp_peer_get(struct interface *ifp,
                                const union sockunion *remote_nbma);
 struct nhrp_peer *nhrp_peer_ref(struct nhrp_peer *p);
index c71b30a2d4b38b7aabab2cfc614b8636faa3ea6f..8cfdf2642c5df1bf2246fcc59338d2b889299213 100644 (file)
@@ -82,10 +82,10 @@ static int ospf6_abr_nexthops_belong_to_area(struct ospf6_route *route,
 static void ospf6_abr_delete_route(struct ospf6_route *range,
                                   struct ospf6_route *summary,
                                   struct ospf6_route_table *summary_table,
-                                  struct ospf6_lsa *old, struct ospf6 *ospf6)
+                                  struct ospf6_lsa *old)
 {
        if (summary) {
-               ospf6_route_remove(summary, summary_table, ospf6);
+               ospf6_route_remove(summary, summary_table);
        }
 
        if (old && !OSPF6_LSA_IS_MAXAGE(old))
@@ -117,7 +117,7 @@ void ospf6_abr_disable_area(struct ospf6_area *area)
                                        area->ospf6->router_id, area->lsdb);
                if (old)
                        ospf6_lsa_purge(old);
-               ospf6_route_remove(ro, area->summary_prefix, area->ospf6);
+               ospf6_route_remove(ro, area->summary_prefix);
        }
 
        /* Withdraw all summary router-routes previously originated */
@@ -128,7 +128,7 @@ void ospf6_abr_disable_area(struct ospf6_area *area)
                                        area->ospf6->router_id, area->lsdb);
                if (old)
                        ospf6_lsa_purge(old);
-               ospf6_route_remove(ro, area->summary_router, area->ospf6);
+               ospf6_route_remove(ro, area->summary_router);
        }
 
        /* Schedule Router-LSA for each area (ABR status may change) */
@@ -271,11 +271,10 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                                                "The range is not active. withdraw");
 
                                ospf6_abr_delete_route(route, summary,
-                                                      summary_table, old,
-                                                      area->ospf6);
+                                                      summary_table, old);
                        }
                } else if (old) {
-                       ospf6_route_remove(summary, summary_table, area->ospf6);
+                       ospf6_route_remove(summary, summary_table);
                        ospf6_lsa_purge(old);
                }
                return 0;
@@ -286,8 +285,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                        zlog_debug(
                                "Area has been stubbed, purge Inter-Router LSA");
 
-               ospf6_abr_delete_route(route, summary, summary_table, old,
-                                      area->ospf6);
+               ospf6_abr_delete_route(route, summary, summary_table, old);
                return 0;
        }
 
@@ -296,8 +294,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                if (is_debug)
                        zlog_debug("Area has been stubbed, purge prefix LSA");
 
-               ospf6_abr_delete_route(route, summary, summary_table, old,
-                                      area->ospf6);
+               ospf6_abr_delete_route(route, summary, summary_table, old);
                return 0;
        }
 
@@ -333,7 +330,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                                zlog_debug(
                                        "This is the secondary path to the ASBR, ignore");
                        ospf6_abr_delete_route(route, summary, summary_table,
-                                              old, area->ospf6);
+                                              old);
                        return 0;
                }
 
@@ -364,7 +361,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                                        "Suppressed by range %pFX of area %s",
                                        &range->prefix, route_area->name);
                        ospf6_abr_delete_route(route, summary, summary_table,
-                                              old, area->ospf6);
+                                              old);
                        return 0;
                }
        }
@@ -377,7 +374,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                                zlog_debug(
                                        "This is the range with DoNotAdvertise set. ignore");
                        ospf6_abr_delete_route(route, summary, summary_table,
-                                              old, area->ospf6);
+                                              old);
                        return 0;
                }
 
@@ -386,7 +383,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                        if (is_debug)
                                zlog_debug("The range is not active. withdraw");
                        ospf6_abr_delete_route(route, summary, summary_table,
-                                              old, area->ospf6);
+                                              old);
                        return 0;
                }
        }
@@ -437,7 +434,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                                summary->path.origin.type,
                                summary->path.origin.adv_router, area->lsdb);
                }
-               summary = ospf6_route_add(summary, summary_table, area->ospf6);
+               summary = ospf6_route_add(summary, summary_table);
        } else {
                summary->type = route->type;
                monotime(&summary->changed);
@@ -706,8 +703,7 @@ void ospf6_abr_defaults_to_stub(struct ospf6 *o)
 
 void ospf6_abr_old_path_update(struct ospf6_route *old_route,
                               struct ospf6_route *route,
-                              struct ospf6_route_table *table,
-                              struct ospf6 *ospf6)
+                              struct ospf6_route_table *table)
 {
        struct ospf6_path *o_path = NULL;
        struct listnode *anode, *anext;
@@ -754,7 +750,7 @@ void ospf6_abr_old_path_update(struct ospf6_route *old_route,
                                           : 0);
 
                if (table->hook_add)
-                       (*table->hook_add)(old_route, ospf6);
+                       (*table->hook_add)(old_route);
 
                if (old_route->path.origin.id == route->path.origin.id &&
                    old_route->path.origin.adv_router ==
@@ -772,8 +768,7 @@ void ospf6_abr_old_path_update(struct ospf6_route *old_route,
 }
 
 void ospf6_abr_old_route_remove(struct ospf6_lsa *lsa, struct ospf6_route *old,
-                               struct ospf6_route_table *table,
-                               struct ospf6 *ospf6)
+                               struct ospf6_route_table *table)
 {
        if (listcount(old->paths) > 1) {
                struct listnode *anode, *anext, *nnode, *rnode, *rnext;
@@ -810,7 +805,7 @@ void ospf6_abr_old_route_remove(struct ospf6_lsa *lsa, struct ospf6_route *old,
                                                                : 0);
 
                                if (table->hook_add)
-                                       (*table->hook_add)(old, ospf6);
+                                       (*table->hook_add)(old);
 
                                if ((old->path.origin.id == lsa->header->id) &&
                                    (old->path.origin.adv_router
@@ -827,10 +822,10 @@ void ospf6_abr_old_route_remove(struct ospf6_lsa *lsa, struct ospf6_route *old,
                                                h_path->origin.adv_router;
                                }
                        } else
-                               ospf6_route_remove(old, table, ospf6);
+                               ospf6_route_remove(old, table);
                }
        } else
-               ospf6_route_remove(old, table, ospf6);
+               ospf6_route_remove(old, table);
 }
 
 /* RFC 2328 16.2. Calculating the inter-area routes */
@@ -945,7 +940,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                if (is_debug)
                        zlog_debug("cost is LS_INFINITY, ignore");
                if (old)
-                       ospf6_abr_old_route_remove(lsa, old, table, oa->ospf6);
+                       ospf6_abr_old_route_remove(lsa, old, table);
                return;
        }
        if (OSPF6_LSA_IS_MAXAGE(lsa)) {
@@ -953,7 +948,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                        zlog_debug("%s: LSA %s is MaxAge, ignore", __func__,
                                   lsa->name);
                if (old)
-                       ospf6_abr_old_route_remove(lsa, old, table, oa->ospf6);
+                       ospf6_abr_old_route_remove(lsa, old, table);
                return;
        }
 
@@ -963,7 +958,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                        zlog_debug("LSA %s is self-originated, ignore",
                                   lsa->name);
                if (old)
-                       ospf6_route_remove(old, table, oa->ospf6);
+                       ospf6_route_remove(old, table);
                return;
        }
 
@@ -979,7 +974,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                                zlog_debug(
                                        "Prefix is equal to address range, ignore");
                        if (old)
-                               ospf6_route_remove(old, table, oa->ospf6);
+                               ospf6_route_remove(old, table);
                        return;
                }
 
@@ -990,7 +985,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                        if (is_debug)
                                zlog_debug("Prefix has NU/LA bit set, ignore");
                        if (old)
-                               ospf6_route_remove(old, table, oa->ospf6);
+                               ospf6_route_remove(old, table);
                        return;
                }
        }
@@ -1003,7 +998,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                        if (is_debug)
                                zlog_debug("Prefix has NU/LA bit set, ignore");
                        if (old)
-                               ospf6_route_remove(old, table, oa->ospf6);
+                               ospf6_route_remove(old, table);
 
                        return;
                }
@@ -1017,7 +1012,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                                        "Ignorning Inter-Router LSA for an ABR (%s)",
                                        buf);
                        if (old)
-                               ospf6_route_remove(old, table, oa->ospf6);
+                               ospf6_route_remove(old, table);
 
                        return;
                }
@@ -1045,7 +1040,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                                        zlog_debug(
                                                "%s: remove old entry: %s %p ",
                                                __func__, buf, (void *)old);
-                               ospf6_route_remove(old, table, oa->ospf6);
+                               ospf6_route_remove(old, table);
                        }
                }
                return;
@@ -1064,8 +1059,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                                        zlog_debug(
                                                "Prefix was denied by import-list");
                                if (old)
-                                       ospf6_route_remove(old, table,
-                                                          oa->ospf6);
+                                       ospf6_route_remove(old, table);
                                return;
                        }
        }
@@ -1077,7 +1071,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                        if (is_debug)
                                zlog_debug("Prefix was denied by prefix-list");
                        if (old)
-                               ospf6_route_remove(old, table, oa->ospf6);
+                               ospf6_route_remove(old, table);
                        return;
                }
        }
@@ -1130,7 +1124,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                         */
                        if (listcount(old_route->paths) > 1)
                                ospf6_abr_old_path_update(old_route, route,
-                                                         table, oa->ospf6);
+                                                         table);
                        continue;
                }
 
@@ -1198,7 +1192,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                 * For Inter-Router trigger summary update
                 */
                if (table->hook_add)
-                       (*table->hook_add)(old_route, oa->ospf6);
+                       (*table->hook_add)(old_route);
 
                /* Delete new route */
                ospf6_route_delete(route);
@@ -1218,7 +1212,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                ospf6_copy_nexthops(path->nh_list, abr_entry->nh_list);
                listnode_add_sort(route->paths, path);
                /* ospf6_ia_add_nw_route (table, &prefix, route); */
-               ospf6_route_add(route, table, oa->ospf6);
+               ospf6_route_add(route, table);
        }
 }
 
index 8ad51a4f8202b33943c608a400d3c415c2ac8d0e..25a73f9203943953d4f5f2bedd4e62962d0c87f6 100644 (file)
@@ -68,7 +68,7 @@ extern void ospf6_abr_originate_summary(struct ospf6_route *route,
                                        struct ospf6 *ospf6);
 extern void ospf6_abr_examin_summary(struct ospf6_lsa *lsa,
                                     struct ospf6_area *oa);
-extern void ospf6_abr_defaults_to_stub(struct ospf6 *);
+extern void ospf6_abr_defaults_to_stub(struct ospf6 *ospf6);
 extern void ospf6_abr_examin_brouter(uint32_t router_id,
                                     struct ospf6_route *route,
                                     struct ospf6 *ospf6);
@@ -81,12 +81,10 @@ extern void install_element_ospf6_debug_abr(void);
 extern int ospf6_abr_config_write(struct vty *vty);
 extern void ospf6_abr_old_route_remove(struct ospf6_lsa *lsa,
                                       struct ospf6_route *old,
-                                      struct ospf6_route_table *table,
-                                      struct ospf6 *ospf6);
+                                      struct ospf6_route_table *table);
 extern void ospf6_abr_old_path_update(struct ospf6_route *old_route,
                                      struct ospf6_route *route,
-                                     struct ospf6_route_table *table,
-                                     struct ospf6 *ospf6);
+                                     struct ospf6_route_table *table);
 extern void ospf6_abr_init(void);
 
 #endif /*OSPF6_ABR_H*/
index e98764cd26d61130663e099d8d14ebb3b967a5d9..778bcb9a457763f63ee72c3e78e9ed175d4c36da 100644 (file)
@@ -115,23 +115,25 @@ static void ospf6_area_lsdb_hook_remove(struct ospf6_lsa *lsa)
        }
 }
 
-static void ospf6_area_route_hook_add(struct ospf6_route *route,
-                                     struct ospf6 *ospf6)
+static void ospf6_area_route_hook_add(struct ospf6_route *route)
 {
+       struct ospf6_area *oa = route->table->scope;
+       struct ospf6 *ospf6 = oa->ospf6;
        struct ospf6_route *copy;
 
        copy = ospf6_route_copy(route);
-       ospf6_route_add(copy, ospf6->route_table, ospf6);
+       ospf6_route_add(copy, ospf6->route_table);
 }
 
-static void ospf6_area_route_hook_remove(struct ospf6_route *route,
-                                        struct ospf6 *ospf6)
+static void ospf6_area_route_hook_remove(struct ospf6_route *route)
 {
+       struct ospf6_area *oa = route->table->scope;
+       struct ospf6 *ospf6 = oa->ospf6;
        struct ospf6_route *copy;
 
        copy = ospf6_route_lookup_identical(route, ospf6->route_table);
        if (copy)
-               ospf6_route_remove(copy, ospf6->route_table, ospf6);
+               ospf6_route_remove(copy, ospf6->route_table);
 }
 
 static void ospf6_area_stub_update(struct ospf6_area *area)
@@ -284,13 +286,13 @@ void ospf6_area_delete(struct ospf6_area *oa)
        ospf6_lsdb_delete(oa->lsdb_self);
        ospf6_lsdb_delete(oa->temp_router_lsa_lsdb);
 
-       ospf6_spf_table_finish(oa->spf_table, oa->ospf6);
-       ospf6_route_table_delete(oa->spf_table, oa->ospf6);
-       ospf6_route_table_delete(oa->route_table, oa->ospf6);
+       ospf6_spf_table_finish(oa->spf_table);
+       ospf6_route_table_delete(oa->spf_table);
+       ospf6_route_table_delete(oa->route_table);
 
-       ospf6_route_table_delete(oa->range_table, oa->ospf6);
-       ospf6_route_table_delete(oa->summary_prefix, oa->ospf6);
-       ospf6_route_table_delete(oa->summary_router, oa->ospf6);
+       ospf6_route_table_delete(oa->range_table);
+       ospf6_route_table_delete(oa->summary_prefix);
+       ospf6_route_table_delete(oa->summary_router);
 
        listnode_delete(oa->ospf6->area_list, oa);
        oa->ospf6 = NULL;
@@ -351,48 +353,102 @@ void ospf6_area_disable(struct ospf6_area *oa)
        ospf6_lsdb_remove_all(oa->lsdb);
        ospf6_lsdb_remove_all(oa->lsdb_self);
 
-       ospf6_spf_table_finish(oa->spf_table, oa->ospf6);
-       ospf6_route_remove_all(oa->route_table, oa->ospf6);
+       ospf6_spf_table_finish(oa->spf_table);
+       ospf6_route_remove_all(oa->route_table);
 
        THREAD_OFF(oa->thread_router_lsa);
        THREAD_OFF(oa->thread_intra_prefix_lsa);
 }
 
 
-void ospf6_area_show(struct vty *vty, struct ospf6_area *oa)
+void ospf6_area_show(struct vty *vty, struct ospf6_area *oa,
+                    json_object *json_areas, bool use_json)
 {
        struct listnode *i;
        struct ospf6_interface *oi;
        unsigned long result;
+       json_object *json_area;
+       json_object *array_interfaces;
 
-       if (!IS_AREA_STUB(oa))
-               vty_out(vty, " Area %s\n", oa->name);
-       else {
-               if (oa->no_summary) {
-                       vty_out(vty, " Area %s[Stub, No Summary]\n", oa->name);
-               } else {
-                       vty_out(vty, " Area %s[Stub]\n", oa->name);
+       if (use_json) {
+               json_area = json_object_new_object();
+               json_object_boolean_add(json_area, "areaIsStub",
+                                       IS_AREA_STUB(oa));
+               if (IS_AREA_STUB(oa)) {
+                       json_object_boolean_add(json_area, "areaNoSummary",
+                                               oa->no_summary);
                }
-       }
-       vty_out(vty, "     Number of Area scoped LSAs is %u\n",
-               oa->lsdb->count);
-
-       vty_out(vty, "     Interface attached to this area:");
-       for (ALL_LIST_ELEMENTS_RO(oa->if_list, i, oi))
-               vty_out(vty, " %s", oi->interface->name);
-       vty_out(vty, "\n");
-
-       if (oa->ts_spf.tv_sec || oa->ts_spf.tv_usec) {
-               result = monotime_since(&oa->ts_spf, NULL);
-               if (result / TIMER_SECOND_MICRO > 0) {
-                       vty_out(vty, "SPF last executed %ld.%lds ago\n",
-                               result / TIMER_SECOND_MICRO,
-                               result % TIMER_SECOND_MICRO);
-               } else {
-                       vty_out(vty, "SPF last executed %ldus ago\n", result);
+
+               json_object_int_add(json_area, "numberOfAreaScopedLsa",
+                                   oa->lsdb->count);
+
+               /* Interfaces Attached */
+               array_interfaces = json_object_new_array();
+               for (ALL_LIST_ELEMENTS_RO(oa->if_list, i, oi))
+                       json_object_array_add(
+                               array_interfaces,
+                               json_object_new_string(oi->interface->name));
+
+               json_object_object_add(json_area, "interfacesAttachedToArea",
+                                      array_interfaces);
+
+               if (oa->ts_spf.tv_sec || oa->ts_spf.tv_usec) {
+                       json_object_boolean_true_add(json_area, "spfHasRun");
+                       result = monotime_since(&oa->ts_spf, NULL);
+                       if (result / TIMER_SECOND_MICRO > 0) {
+                               json_object_int_add(
+                                       json_area, "spfLastExecutedSecs",
+                                       result / TIMER_SECOND_MICRO);
+
+                               json_object_int_add(
+                                       json_area, "spfLastExecutedMicroSecs",
+                                       result % TIMER_SECOND_MICRO);
+                       } else {
+                               json_object_int_add(json_area,
+                                                   "spfLastExecutedSecs", 0);
+                               json_object_int_add(json_area,
+                                                   "spfLastExecutedMicroSecs",
+                                                   result);
+                       }
+               } else
+                       json_object_boolean_false_add(json_area, "spfHasRun");
+
+
+               json_object_object_add(json_areas, oa->name, json_area);
+
+       } else {
+
+               if (!IS_AREA_STUB(oa))
+                       vty_out(vty, " Area %s\n", oa->name);
+               else {
+                       if (oa->no_summary) {
+                               vty_out(vty, " Area %s[Stub, No Summary]\n",
+                                       oa->name);
+                       } else {
+                               vty_out(vty, " Area %s[Stub]\n", oa->name);
+                       }
                }
-       } else
-               vty_out(vty, "SPF has not been run\n");
+               vty_out(vty, "     Number of Area scoped LSAs is %u\n",
+                       oa->lsdb->count);
+
+               vty_out(vty, "     Interface attached to this area:");
+               for (ALL_LIST_ELEMENTS_RO(oa->if_list, i, oi))
+                       vty_out(vty, " %s", oi->interface->name);
+               vty_out(vty, "\n");
+
+               if (oa->ts_spf.tv_sec || oa->ts_spf.tv_usec) {
+                       result = monotime_since(&oa->ts_spf, NULL);
+                       if (result / TIMER_SECOND_MICRO > 0) {
+                               vty_out(vty, "SPF last executed %ld.%lds ago\n",
+                                       result / TIMER_SECOND_MICRO,
+                                       result % TIMER_SECOND_MICRO);
+                       } else {
+                               vty_out(vty, "SPF last executed %ldus ago\n",
+                                       result);
+                       }
+               } else
+                       vty_out(vty, "SPF has not been run\n");
+       }
 }
 
 DEFUN (area_range,
@@ -454,7 +510,7 @@ DEFUN (area_range,
        zlog_debug("%s: for prefix %s, flag = %x", __func__,
                   argv[idx_ipv6_prefixlen]->arg, range->flag);
        if (range->rnode == NULL) {
-               ospf6_route_add(range, oa->range_table, oa->ospf6);
+               ospf6_route_add(range, oa->range_table);
        }
 
        if (ospf6_is_router_abr(ospf6)) {
@@ -515,7 +571,7 @@ DEFUN (no_area_range,
                /* purge the old aggregated summary LSA */
                ospf6_abr_originate_summary(range, oa->ospf6);
        }
-       ospf6_route_remove(range, oa->range_table, oa->ospf6);
+       ospf6_route_remove(range, oa->range_table);
 
        return CMD_SUCCESS;
 }
@@ -924,15 +980,15 @@ DEFUN (show_ipv6_ospf6_simulate_spf_tree_root,
 
        route = ospf6_route_lookup(&prefix, spf_table);
        if (route == NULL) {
-               ospf6_spf_table_finish(spf_table, ospf6);
-               ospf6_route_table_delete(spf_table, ospf6);
+               ospf6_spf_table_finish(spf_table);
+               ospf6_route_table_delete(spf_table);
                return CMD_SUCCESS;
        }
        root = (struct ospf6_vertex *)route->route_option;
        ospf6_spf_display_subtree(vty, "", 0, root);
 
-       ospf6_spf_table_finish(spf_table, ospf6);
-       ospf6_route_table_delete(spf_table, ospf6);
+       ospf6_spf_table_finish(spf_table);
+       ospf6_route_table_delete(spf_table);
 
        return CMD_SUCCESS;
 }
index 2097ef6e43c61ec4d59da7068457664b01457077..8a58b2a50ed571da8dc46e6f8dc7e4e75b4d2107 100644 (file)
@@ -22,6 +22,7 @@
 #define OSPF_AREA_H
 
 #include "ospf6_top.h"
+#include "lib/json.h"
 
 struct ospf6_area {
        /* Reference to Top data structure */
@@ -143,7 +144,8 @@ extern struct ospf6_area *ospf6_area_lookup_by_area_id(uint32_t area_id);
 extern void ospf6_area_enable(struct ospf6_area *);
 extern void ospf6_area_disable(struct ospf6_area *);
 
-extern void ospf6_area_show(struct vty *, struct ospf6_area *);
+extern void ospf6_area_show(struct vty *, struct ospf6_area *,
+                           json_object *json_areas, bool use_json);
 
 extern void ospf6_area_plist_update(struct prefix_list *plist, int add);
 extern void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6);
index 1d222d5568c6fb244f041fa6bedd32a00f70cbf7..0e419cbff6e5d97dd9a925cac9e7ce91e2f51afb 100644 (file)
 #include "ospf6_intra.h"
 #include "ospf6_flood.h"
 #include "ospf6d.h"
+#include "lib/json.h"
 
 static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id);
-static void ospf6_asbr_redistribute_unset(int type, vrf_id_t vrf_id);
+static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
+                                         struct ospf6_redist *red, int type);
 
 unsigned char conf_debug_ospf6_asbr = 0;
 
@@ -286,7 +288,7 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
                                 */
                                if (ospf6->route_table->hook_add)
                                        (*ospf6->route_table->hook_add)(
-                                               old_route, ospf6);
+                                               old_route);
 
                                if (old_route->path.origin.id
                                            == route->path.origin.id
@@ -314,7 +316,7 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
                                                route->path.cost);
                                }
                                ospf6_route_remove(old_route,
-                                                  ospf6->route_table, ospf6);
+                                                  ospf6->route_table);
                        }
                }
                if (route_updated)
@@ -424,8 +426,7 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
 
                        /* Update RIB/FIB */
                        if (ospf6->route_table->hook_add)
-                               (*ospf6->route_table->hook_add)(old_route,
-                                                               ospf6);
+                               (*ospf6->route_table->hook_add)(old_route);
 
                        /* Delete the new route its info added to existing
                         * route.
@@ -438,16 +439,17 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
 
        if (!route_found) {
                /* Add new route to existing node in ospf6 route table. */
-               ospf6_route_add(route, ospf6->route_table, ospf6);
+               ospf6_route_add(route, ospf6->route_table);
        }
 }
 
-void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa, struct ospf6 *ospf6)
+void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
 {
        struct ospf6_as_external_lsa *external;
        struct prefix asbr_id;
        struct ospf6_route *asbr_entry, *route, *old;
        struct ospf6_path *path;
+       struct ospf6 *ospf6;
 
        external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
                lsa->header);
@@ -455,6 +457,8 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa, struct ospf6 *ospf6)
        if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
                zlog_debug("Calculate AS-External route for %s", lsa->name);
 
+       ospf6 = ospf6_get_by_lsdb(lsa);
+
        if (lsa->header->adv_router == ospf6->router_id) {
                if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
                        zlog_debug("Ignore self-originated AS-External-LSA");
@@ -530,7 +534,7 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa, struct ospf6 *ospf6)
        old = ospf6_route_lookup(&route->prefix, ospf6->route_table);
        if (!old) {
                /* Add the new route to ospf6 instance route table. */
-               ospf6_route_add(route, ospf6->route_table, ospf6);
+               ospf6_route_add(route, ospf6->route_table);
        } else {
                /* RFC 2328 16.4 (6)
                 * ECMP: Keep new equal preference path in current
@@ -732,8 +736,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
                                         */
                                        if (oa->ospf6->route_table->hook_add)
                                                (*oa->ospf6->route_table
-                                                         ->hook_add)(
-                                                       route, oa->ospf6);
+                                                         ->hook_add)(route);
 
                                        /* route's primary path is similar
                                         * to LSA, replace route's primary
@@ -757,8 +760,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
                                        }
                                } else {
                                        ospf6_route_remove(
-                                               route, oa->ospf6->route_table,
-                                               oa->ospf6);
+                                               route, oa->ospf6->route_table);
                                }
                        }
                        continue;
@@ -798,7 +800,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
                                &route->prefix, route->path.cost, route->path.u.cost_e2,
                                listcount(route->nh_list));
                }
-               ospf6_route_remove(route, oa->ospf6->route_table, oa->ospf6);
+               ospf6_route_remove(route, oa->ospf6->route_table);
        }
        if (route != NULL)
                ospf6_route_unlock(route);
@@ -824,7 +826,7 @@ void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry, struct ospf6 *ospf6)
        router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix);
        for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa)) {
                if (!OSPF6_LSA_IS_MAXAGE(lsa))
-                       ospf6_asbr_lsa_add(lsa, ospf6);
+                       ospf6_asbr_lsa_add(lsa);
        }
 }
 
@@ -843,35 +845,28 @@ void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry,
 
 
 /* redistribute function */
-
-static void ospf6_asbr_routemap_set(int type, const char *mapname,
-                                   uint32_t vrf_id)
+static void ospf6_asbr_routemap_set(struct ospf6_redist *red,
+                                   const char *mapname)
 {
-       struct ospf6 *ospf6 = NULL;
-
-       ospf6 = ospf6_lookup_by_vrf_id(vrf_id);
-
-       if (ospf6 == NULL)
-               return;
-
-       if (ospf6->rmap[type].name) {
-               route_map_counter_decrement(ospf6->rmap[type].map);
-               free(ospf6->rmap[type].name);
+       if (ROUTEMAP_NAME(red)) {
+               route_map_counter_decrement(ROUTEMAP(red));
+               free(ROUTEMAP_NAME(red));
        }
-       ospf6->rmap[type].name = strdup(mapname);
-       ospf6->rmap[type].map = route_map_lookup_by_name(mapname);
-       route_map_counter_increment(ospf6->rmap[type].map);
+
+       ROUTEMAP_NAME(red) = strdup(mapname);
+       ROUTEMAP(red) = route_map_lookup_by_name(mapname);
+       route_map_counter_increment(ROUTEMAP(red));
 }
 
-static void ospf6_asbr_routemap_unset(int type, struct ospf6 *ospf6)
+static void ospf6_asbr_routemap_unset(struct ospf6_redist *red)
 {
-       if (ospf6->rmap[type].name)
-               free(ospf6->rmap[type].name);
+       if (ROUTEMAP_NAME(red))
+               free(ROUTEMAP_NAME(red));
 
-       route_map_counter_decrement(ospf6->rmap[type].map);
+       route_map_counter_decrement(ROUTEMAP(red));
 
-       ospf6->rmap[type].name = NULL;
-       ospf6->rmap[type].map = NULL;
+       ROUTEMAP_NAME(red) = NULL;
+       ROUTEMAP(red) = NULL;
 }
 
 static int ospf6_asbr_routemap_update_timer(struct thread *thread)
@@ -879,6 +874,7 @@ static int ospf6_asbr_routemap_update_timer(struct thread *thread)
        void **arg;
        int arg_type;
        struct ospf6 *ospf6;
+       struct ospf6_redist *red;
 
        arg = THREAD_ARG(thread);
        ospf6 = (struct ospf6 *)arg[0];
@@ -886,13 +882,14 @@ static int ospf6_asbr_routemap_update_timer(struct thread *thread)
 
        ospf6->t_distribute_update = NULL;
 
-       if (ospf6->rmap[arg_type].name)
-               ospf6->rmap[arg_type].map =
-                       route_map_lookup_by_name(ospf6->rmap[arg_type].name);
-       if (ospf6->rmap[arg_type].map) {
+       red = ospf6_redist_lookup(ospf6, arg_type, 0);
+
+       if (red && ROUTEMAP_NAME(red))
+               ROUTEMAP(red) = route_map_lookup_by_name(ROUTEMAP_NAME(red));
+       if (red && ROUTEMAP(red)) {
                if (IS_OSPF6_DEBUG_ASBR)
                        zlog_debug("%s: route-map %s update, reset redist %s",
-                                  __func__, ospf6->rmap[arg_type].name,
+                                  __func__, ROUTEMAP_NAME(red),
                                   ZROUTE_NAME(arg_type));
 
                ospf6_zebra_no_redistribute(arg_type, ospf6->vrf_id);
@@ -930,20 +927,23 @@ static void ospf6_asbr_routemap_update(const char *mapname)
        int type;
        struct listnode *node, *nnode;
        struct ospf6 *ospf6 = NULL;
+       struct ospf6_redist *red;
 
        if (om6 == NULL)
                return;
 
        for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
                for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
-                       if (ospf6->rmap[type].name == NULL)
+                       red = ospf6_redist_lookup(ospf6, type, 0);
+                       if (!red || (ROUTEMAP_NAME(red) == NULL))
                                continue;
-                       ospf6->rmap[type].map = route_map_lookup_by_name(
-                                       ospf6->rmap[type].name);
+                       ROUTEMAP(red) =
+                               route_map_lookup_by_name(ROUTEMAP_NAME(red));
 
-                       if (mapname == NULL || strcmp(ospf6->rmap[type].name, mapname))
+                       if (mapname == NULL
+                           || strcmp(ROUTEMAP_NAME(red), mapname))
                                continue;
-                       if (ospf6->rmap[type].map) {
+                       if (ROUTEMAP(red)) {
                                if (IS_OSPF6_DEBUG_ASBR)
                                        zlog_debug(
                                                        "%s: route-map %s update, reset redist %s",
@@ -952,11 +952,9 @@ static void ospf6_asbr_routemap_update(const char *mapname)
                                                        ZROUTE_NAME(
                                                                type));
 
-                                       route_map_counter_increment(
-                                                       ospf6->rmap[type].map);
+                               route_map_counter_increment(ROUTEMAP(red));
 
-                                       ospf6_asbr_distribute_list_update(
-                                                       type, ospf6);
+                               ospf6_asbr_distribute_list_update(type, ospf6);
                        } else {
                                /*
                                * if the mapname matches a
@@ -972,11 +970,8 @@ static void ospf6_asbr_routemap_update(const char *mapname)
                                                        mapname,
                                                        ZROUTE_NAME(
                                                                type));
-                               ospf6_asbr_redistribute_unset(
-                                               type, ospf6->vrf_id);
-                               ospf6_asbr_routemap_set(
-                                               type, mapname,
-                                               ospf6->vrf_id);
+                               ospf6_asbr_redistribute_unset(ospf6, red, type);
+                               ospf6_asbr_routemap_set(red, mapname);
                                ospf6_asbr_redistribute_set(
                                                type, ospf6->vrf_id);
                        }
@@ -989,13 +984,15 @@ static void ospf6_asbr_routemap_event(const char *name)
        int type;
        struct listnode *node, *nnode;
        struct ospf6 *ospf6;
+       struct ospf6_redist *red;
 
        if (om6 == NULL)
                return;
        for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
                for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
-                       if ((ospf6->rmap[type].name)
-                           && (strcmp(ospf6->rmap[type].name, name) == 0))
+                       red = ospf6_redist_lookup(ospf6, type, 0);
+                       if (red && ROUTEMAP_NAME(red)
+                           && (strcmp(ROUTEMAP_NAME(red), name) == 0))
                                ospf6_asbr_distribute_list_update(type, ospf6);
                }
        }
@@ -1006,23 +1003,70 @@ int ospf6_asbr_is_asbr(struct ospf6 *o)
        return o->external_table->count;
 }
 
+struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type,
+                                        unsigned short instance)
+{
+       struct list *red_list;
+       struct listnode *node;
+       struct ospf6_redist *red;
+
+       red_list = ospf6->redist[type];
+       if (!red_list)
+               return (NULL);
+
+       for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
+               if (red->instance == instance)
+                       return red;
+
+       return NULL;
+}
+
+static struct ospf6_redist *ospf6_redist_add(struct ospf6 *ospf6, int type,
+                                            uint8_t instance)
+{
+       struct ospf6_redist *red;
+
+       red = ospf6_redist_lookup(ospf6, type, instance);
+       if (red)
+               return red;
+
+       if (!ospf6->redist[type])
+               ospf6->redist[type] = list_new();
+
+       red = XCALLOC(MTYPE_OSPF6_REDISTRIBUTE, sizeof(struct ospf6_redist));
+       red->instance = instance;
+       ROUTEMAP_NAME(red) = NULL;
+       ROUTEMAP(red) = NULL;
+
+       listnode_add(ospf6->redist[type], red);
+
+       return red;
+}
+
+static void ospf6_redist_del(struct ospf6 *ospf6, struct ospf6_redist *red,
+                            int type)
+{
+       if (red) {
+               listnode_delete(ospf6->redist[type], red);
+               if (!ospf6->redist[type]->count) {
+                       list_delete(&ospf6->redist[type]);
+               }
+               XFREE(MTYPE_OSPF6_REDISTRIBUTE, red);
+       }
+}
+
 static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id)
 {
        ospf6_zebra_redistribute(type, vrf_id);
 }
 
-static void ospf6_asbr_redistribute_unset(int type, vrf_id_t vrf_id)
+static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
+                                         struct ospf6_redist *red, int type)
 {
        struct ospf6_route *route;
        struct ospf6_external_info *info;
-       struct ospf6 *ospf6 = NULL;
-
-       ospf6 = ospf6_lookup_by_vrf_id(vrf_id);
-
-       if (ospf6 == NULL)
-               return;
 
-       ospf6_zebra_no_redistribute(type, vrf_id);
+       ospf6_zebra_no_redistribute(type, ospf6->vrf_id);
 
        for (route = ospf6_route_head(ospf6->external_table); route;
             route = ospf6_route_next(route)) {
@@ -1034,7 +1078,7 @@ static void ospf6_asbr_redistribute_unset(int type, vrf_id_t vrf_id)
                                               ospf6);
        }
 
-       ospf6_asbr_routemap_unset(type, ospf6);
+       ospf6_asbr_routemap_unset(red);
 }
 
 /* When an area is unstubified, flood all the external LSAs in the area */
@@ -1067,6 +1111,12 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
        char ibuf[16];
        struct listnode *lnode, *lnnode;
        struct ospf6_area *oa;
+       struct ospf6_redist *red;
+
+       red = ospf6_redist_lookup(ospf6, type, 0);
+
+       if (!red)
+               return;
 
        if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id))
                return;
@@ -1078,28 +1128,28 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
                zlog_debug("Redistribute %pFX (%s)", prefix, ZROUTE_NAME(type));
 
        /* if route-map was specified but not found, do not advertise */
-       if (ospf6->rmap[type].name) {
-               if (ospf6->rmap[type].map == NULL)
+       if (ROUTEMAP_NAME(red)) {
+               if (ROUTEMAP(red) == NULL)
                        ospf6_asbr_routemap_update(NULL);
-               if (ospf6->rmap[type].map == NULL) {
+               if (ROUTEMAP(red) == NULL) {
                        zlog_warn(
                                "route-map \"%s\" not found, suppress redistributing",
-                               ospf6->rmap[type].name);
+                               ROUTEMAP_NAME(red));
                        return;
                }
        }
 
        /* apply route-map */
-       if (ospf6->rmap[type].map) {
+       if (ROUTEMAP(red)) {
                troute.route_option = &tinfo;
                tinfo.ifindex = ifindex;
                tinfo.tag = tag;
 
-               ret = route_map_apply(ospf6->rmap[type].map, prefix, &troute);
+               ret = route_map_apply(ROUTEMAP(red), prefix, &troute);
                if (ret == RMAP_DENYMATCH) {
                        if (IS_OSPF6_DEBUG_ASBR)
                                zlog_debug("Denied by route-map \"%s\"",
-                                          ospf6->rmap[type].name);
+                                          ROUTEMAP_NAME(red));
                        ospf6_asbr_redistribute_remove(type, ifindex, prefix,
                                                       ospf6);
                        return;
@@ -1110,7 +1160,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
        if (match) {
                info = match->route_option;
                /* copy result of route-map */
-               if (ospf6->rmap[type].map) {
+               if (ROUTEMAP(red)) {
                        if (troute.path.metric_type)
                                match->path.metric_type =
                                        troute.path.metric_type;
@@ -1163,7 +1213,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
        info->id = ospf6->external_id++;
 
        /* copy result of route-map */
-       if (ospf6->rmap[type].map) {
+       if (ROUTEMAP(red)) {
                if (troute.path.metric_type)
                        route->path.metric_type = troute.path.metric_type;
                if (troute.path.cost)
@@ -1190,7 +1240,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
        node = route_node_get(ospf6->external_id_table, &prefix_id);
        node->info = route;
 
-       route = ospf6_route_add(route, ospf6->external_table, ospf6);
+       route = ospf6_route_add(route, ospf6->external_table);
        route->route_option = info;
 
        if (IS_OSPF6_DEBUG_ASBR) {
@@ -1256,7 +1306,7 @@ void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
        route_unlock_node(node); /* to free the lookup lock */
        route_unlock_node(node); /* to free the original lock */
 
-       ospf6_route_remove(match, ospf6->external_table, ospf6);
+       ospf6_route_remove(match, ospf6->external_table);
        XFREE(MTYPE_OSPF6_EXTERNAL_INFO, info);
 
        /* Router-Bit (ASBR Flag) may have to be updated */
@@ -1271,6 +1321,7 @@ DEFUN (ospf6_redistribute,
        FRR_REDIST_HELP_STR_OSPF6D)
 {
        int type;
+       struct ospf6_redist *red;
 
        VTY_DECLVAR_CONTEXT(ospf6, ospf6);
        OSPF6_CMD_CHECK_RUNNING(ospf6);
@@ -1279,8 +1330,13 @@ DEFUN (ospf6_redistribute,
        if (type < 0)
                return CMD_WARNING_CONFIG_FAILED;
 
-       ospf6_asbr_redistribute_unset(type, ospf6->vrf_id);
+       red = ospf6_redist_add(ospf6, type, 0);
+       if (!red)
+               return CMD_SUCCESS;
+
+       ospf6_asbr_redistribute_unset(ospf6, red, type);
        ospf6_asbr_redistribute_set(type, ospf6->vrf_id);
+
        return CMD_SUCCESS;
 }
 
@@ -1295,6 +1351,7 @@ DEFUN (ospf6_redistribute_routemap,
        int idx_protocol = 1;
        int idx_word = 3;
        int type;
+       struct ospf6_redist *red;
 
        VTY_DECLVAR_CONTEXT(ospf6, ospf6);
        OSPF6_CMD_CHECK_RUNNING(ospf6);
@@ -1304,9 +1361,14 @@ DEFUN (ospf6_redistribute_routemap,
        if (type < 0)
                return CMD_WARNING_CONFIG_FAILED;
 
-       ospf6_asbr_redistribute_unset(type, ospf6->vrf_id);
-       ospf6_asbr_routemap_set(type, argv[idx_word]->arg, ospf6->vrf_id);
+       red = ospf6_redist_add(ospf6, type, 0);
+       if (!red)
+               return CMD_SUCCESS;
+
+       ospf6_asbr_redistribute_unset(ospf6, red, type);
+       ospf6_asbr_routemap_set(red, argv[idx_word]->arg);
        ospf6_asbr_redistribute_set(type, ospf6->vrf_id);
+
        return CMD_SUCCESS;
 }
 
@@ -1321,6 +1383,7 @@ DEFUN (no_ospf6_redistribute,
 {
        int idx_protocol = 2;
        int type;
+       struct ospf6_redist *red;
 
        VTY_DECLVAR_CONTEXT(ospf6, ospf6);
 
@@ -1331,7 +1394,12 @@ DEFUN (no_ospf6_redistribute,
        if (type < 0)
                return CMD_WARNING_CONFIG_FAILED;
 
-       ospf6_asbr_redistribute_unset(type, ospf6->vrf_id);
+       red = ospf6_redist_lookup(ospf6, type, 0);
+       if (!red)
+               return CMD_SUCCESS;
+
+       ospf6_asbr_redistribute_unset(ospf6, red, type);
+       ospf6_redist_del(ospf6, red, type);
 
        return CMD_SUCCESS;
 }
@@ -1339,16 +1407,18 @@ DEFUN (no_ospf6_redistribute,
 int ospf6_redistribute_config_write(struct vty *vty, struct ospf6 *ospf6)
 {
        int type;
+       struct ospf6_redist *red;
 
        for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
-               if (type == ZEBRA_ROUTE_OSPF6)
+               red = ospf6_redist_lookup(ospf6, type, 0);
+               if (!red)
                        continue;
-               if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id))
+               if (type == ZEBRA_ROUTE_OSPF6)
                        continue;
 
-               if (ospf6->rmap[type].name)
+               if (ROUTEMAP_NAME(red))
                        vty_out(vty, " redistribute %s route-map %s\n",
-                               ZROUTE_NAME(type), ospf6->rmap[type].name);
+                               ZROUTE_NAME(type), ROUTEMAP_NAME(red));
                else
                        vty_out(vty, " redistribute %s\n", ZROUTE_NAME(type));
        }
@@ -1356,13 +1426,17 @@ int ospf6_redistribute_config_write(struct vty *vty, struct ospf6 *ospf6)
        return 0;
 }
 
-static void ospf6_redistribute_show_config(struct vty *vty, struct ospf6 *ospf6)
+static void ospf6_redistribute_show_config(struct vty *vty, struct ospf6 *ospf6,
+                                          json_object *json_array,
+                                          json_object *json, bool use_json)
 {
        int type;
        int nroute[ZEBRA_ROUTE_MAX];
        int total;
        struct ospf6_route *route;
        struct ospf6_external_info *info;
+       json_object *json_route;
+       struct ospf6_redist *red;
 
        total = 0;
        for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
@@ -1374,24 +1448,58 @@ static void ospf6_redistribute_show_config(struct vty *vty, struct ospf6 *ospf6)
                total++;
        }
 
-       vty_out(vty, "Redistributing External Routes from:\n");
+       if (use_json)
+               json_route = json_object_new_object();
+       else
+               vty_out(vty, "Redistributing External Routes from:\n");
+
        for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
-               if (type == ZEBRA_ROUTE_OSPF6)
+               red = ospf6_redist_lookup(ospf6, type, 0);
+
+               if (!red)
                        continue;
-               if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id))
+               if (type == ZEBRA_ROUTE_OSPF6)
                        continue;
 
-               if (ospf6->rmap[type].name)
-                       vty_out(vty, "    %d: %s with route-map \"%s\"%s\n",
-                               nroute[type], ZROUTE_NAME(type),
-                               ospf6->rmap[type].name,
-                               (ospf6->rmap[type].map ? ""
+               if (use_json) {
+                       json_object_string_add(json_route, "routeType",
+                                              ZROUTE_NAME(type));
+                       json_object_int_add(json_route, "numberOfRoutes",
+                                           nroute[type]);
+                       json_object_boolean_add(json_route,
+                                               "routeMapNamePresent",
+                                               ROUTEMAP_NAME(red));
+               }
+
+               if (ROUTEMAP_NAME(red)) {
+                       if (use_json) {
+                               json_object_string_add(json_route,
+                                                      "routeMapName",
+                                                      ROUTEMAP_NAME(red));
+                               json_object_boolean_add(json_route,
+                                                       "routeMapFound",
+                                                       ROUTEMAP(red));
+                       } else
+                               vty_out(vty,
+                                       "    %d: %s with route-map \"%s\"%s\n",
+                                       nroute[type], ZROUTE_NAME(type),
+                                       ROUTEMAP_NAME(red),
+                                       (ROUTEMAP(red) ? ""
                                                       : " (not found !)"));
-               else
-                       vty_out(vty, "    %d: %s\n", nroute[type],
-                               ZROUTE_NAME(type));
+               } else {
+                       if (!use_json)
+                               vty_out(vty, "    %d: %s\n", nroute[type],
+                                       ZROUTE_NAME(type));
+               }
+
+               if (use_json)
+                       json_object_array_add(json_array, json_route);
        }
-       vty_out(vty, "Total %d routes\n", total);
+       if (use_json) {
+               json_object_object_add(json, "redistributedRoutes", json_array);
+               json_object_int_add(json, "totalRoutes", total);
+       } else
+               vty_out(vty, "Total %d routes\n", total);
 }
 
 
@@ -1831,12 +1939,17 @@ static int ospf6_as_external_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)
 }
 
 static void ospf6_asbr_external_route_show(struct vty *vty,
-                                          struct ospf6_route *route)
+                                          struct ospf6_route *route,
+                                          json_object *json_array,
+                                          bool use_json)
 {
        struct ospf6_external_info *info = route->route_option;
-       char id[16], forwarding[64];
+       char prefix[PREFIX2STR_BUFFER], id[16], forwarding[64];
        uint32_t tmp_id;
+       json_object *json_route;
+       char route_type[2];
 
+       prefix2str(&route->prefix, prefix, sizeof(prefix));
        tmp_id = ntohl(info->id);
        inet_ntop(AF_INET, &tmp_id, id, sizeof(id));
        if (!IN6_IS_ADDR_UNSPECIFIED(&info->forwarding))
@@ -1846,36 +1959,74 @@ static void ospf6_asbr_external_route_show(struct vty *vty,
                snprintf(forwarding, sizeof(forwarding), ":: (ifindex %d)",
                         ospf6_route_get_first_nh_index(route));
 
-       vty_out(vty, "%c %-32pFX %-15s type-%d %5lu %s\n",
-               zebra_route_char(info->type), &route->prefix, id,
-               route->path.metric_type,
-               (unsigned long)(route->path.metric_type == 2
-                                       ? route->path.u.cost_e2
-                                       : route->path.cost),
-               forwarding);
+       if (use_json) {
+               json_route = json_object_new_object();
+               snprintf(route_type, sizeof(route_type), "%c",
+                        zebra_route_char(info->type));
+               json_object_string_add(json_route, "routeType", route_type);
+               json_object_string_add(json_route, "destination", prefix);
+               json_object_string_add(json_route, "id", id);
+               json_object_int_add(json_route, "metricType",
+                                   route->path.metric_type);
+               json_object_int_add(
+                       json_route, "routeCost",
+                       (unsigned long)(route->path.metric_type == 2
+                                               ? route->path.u.cost_e2
+                                               : route->path.cost));
+               json_object_string_add(json_route, "forwarding", forwarding);
+
+               json_object_array_add(json_array, json_route);
+       } else
+
+               vty_out(vty, "%c %-32pFX %-15s type-%d %5lu %s\n",
+                       zebra_route_char(info->type), &route->prefix, id,
+                       route->path.metric_type,
+                       (unsigned long)(route->path.metric_type == 2
+                                               ? route->path.u.cost_e2
+                                               : route->path.cost),
+                       forwarding);
 }
 
 DEFUN (show_ipv6_ospf6_redistribute,
        show_ipv6_ospf6_redistribute_cmd,
-       "show ipv6 ospf6 redistribute",
+       "show ipv6 ospf6 redistribute [json]",
        SHOW_STR
        IP6_STR
        OSPF6_STR
        "redistributing External information\n"
-       )
+       JSON_STR)
 {
        struct ospf6_route *route;
        struct ospf6 *ospf6 = NULL;
+       json_object *json = NULL;
+       bool uj = use_json(argc, argv);
+       json_object *json_array_routes = NULL;
+       json_object *json_array_redistribute = NULL;
 
        ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
        OSPF6_CMD_CHECK_RUNNING(ospf6);
 
-       ospf6_redistribute_show_config(vty, ospf6);
+       if (uj) {
+               json = json_object_new_object();
+               json_array_routes = json_object_new_array();
+               json_array_redistribute = json_object_new_array();
+       }
+       ospf6_redistribute_show_config(vty, ospf6, json_array_redistribute,
+                                      json, uj);
 
        for (route = ospf6_route_head(ospf6->external_table); route;
-            route = ospf6_route_next(route))
-               ospf6_asbr_external_route_show(vty, route);
+            route = ospf6_route_next(route)) {
+               ospf6_asbr_external_route_show(vty, route, json_array_routes,
+                                              uj);
+       }
 
+       if (uj) {
+               json_object_object_add(json, "routes", json_array_routes);
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
        return CMD_SUCCESS;
 }
 
@@ -1900,15 +2051,21 @@ void ospf6_asbr_init(void)
        install_element(OSPF6_NODE, &no_ospf6_redistribute_cmd);
 }
 
-void ospf6_asbr_redistribute_reset(vrf_id_t vrf_id)
+void ospf6_asbr_redistribute_reset(struct ospf6 *ospf6)
 {
        int type;
+       struct ospf6_redist *red;
 
        for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
+               red = ospf6_redist_lookup(ospf6, type, 0);
+               if (!red)
+                       continue;
                if (type == ZEBRA_ROUTE_OSPF6)
                        continue;
-               if (ospf6_zebra_is_redistribute(type, vrf_id))
-                       ospf6_asbr_redistribute_unset(type, vrf_id);
+               if (ospf6_zebra_is_redistribute(type, ospf6->vrf_id)) {
+                       ospf6_asbr_redistribute_unset(ospf6, red, type);
+                       ospf6_redist_del(ospf6, red, type);
+               }
        }
 }
 
index 46c99706acf0ba5e480abca844f4c21c99245265..fd14610042471991f3c38bbffdd180df62dc84a4 100644 (file)
@@ -70,7 +70,7 @@ struct ospf6_as_external_lsa {
                (E)->bits_metric |= htonl(0x00ffffff) & htonl(C);              \
        }
 
-extern void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa, struct ospf6 *ospf6);
+extern void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa);
 extern void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
                                  struct ospf6_route *asbr_entry);
 extern void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry,
@@ -92,7 +92,7 @@ extern int ospf6_redistribute_config_write(struct vty *vty,
                                           struct ospf6 *ospf6);
 
 extern void ospf6_asbr_init(void);
-extern void ospf6_asbr_redistribute_reset(vrf_id_t vrf_id);
+extern void ospf6_asbr_redistribute_reset(struct ospf6 *ospf6);
 extern void ospf6_asbr_terminate(void);
 extern void ospf6_asbr_send_externals_to_area(struct ospf6_area *);
 
@@ -102,5 +102,6 @@ extern void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
                                              struct ospf6_route *route,
                                              struct ospf6 *ospf6);
 extern void ospf6_asbr_distribute_list_update(int type, struct ospf6 *ospf6);
-
+struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type,
+                                        unsigned short instance);
 #endif /* OSPF6_ASBR_H */
index 1351602619951291e823d5e292c834ba9e0e62a2..4988cee7d860b9b194eecd14aca75ac8524d3961 100644 (file)
@@ -261,7 +261,7 @@ void ospf6_interface_delete(struct ospf6_interface *oi)
        ospf6_lsdb_delete(oi->lsupdate_list);
        ospf6_lsdb_delete(oi->lsack_list);
 
-       ospf6_route_table_delete(oi->route_connected, oi->area->ospf6);
+       ospf6_route_table_delete(oi->route_connected);
 
        /* cut link */
        oi->interface->info = NULL;
@@ -417,7 +417,7 @@ void ospf6_interface_connected_route_update(struct interface *ifp)
                return;
 
        /* update "route to advertise" interface route table */
-       ospf6_route_remove_all(oi->route_connected, oi->area->ospf6);
+       ospf6_route_remove_all(oi->route_connected);
 
        for (ALL_LIST_ELEMENTS(oi->interface->connected, node, nnode, c)) {
                if (c->address->family != AF_INET6)
@@ -461,7 +461,7 @@ void ospf6_interface_connected_route_update(struct interface *ifp)
                inet_pton(AF_INET6, "::1", &nh_addr);
                ospf6_route_add_nexthop(route, oi->interface->ifindex,
                                        &nh_addr);
-               ospf6_route_add(route, oi->route_connected, oi->area->ospf6);
+               ospf6_route_add(route, oi->route_connected);
        }
 
        /* create new Link-LSA */
@@ -507,6 +507,7 @@ static void ospf6_interface_state_change(uint8_t next_state,
                          IPV6_JOIN_GROUP, ospf6->fd);
 
        OSPF6_ROUTER_LSA_SCHEDULE(oi->area);
+       OSPF6_LINK_LSA_SCHEDULE(oi);
        if (next_state == OSPF6_INTERFACE_DOWN) {
                OSPF6_NETWORK_LSA_EXECUTE(oi);
                OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi);
@@ -1217,18 +1218,20 @@ DEFUN(show_ipv6_ospf6_interface,
 
 static int ospf6_interface_show_traffic(struct vty *vty,
                                        struct interface *intf_ifp,
-                                       int display_once)
+                                       int display_once, json_object *json,
+                                       bool use_json)
 {
        struct interface *ifp;
        struct vrf *vrf = NULL;
        struct ospf6_interface *oi = NULL;
+       json_object *json_interface;
 
        if (intf_ifp)
                vrf = vrf_lookup_by_id(intf_ifp->vrf_id);
        else
                vrf = vrf_lookup_by_id(VRF_DEFAULT);
 
-       if (!display_once) {
+       if (!display_once && !use_json) {
                vty_out(vty, "\n");
                vty_out(vty, "%-12s%-17s%-17s%-17s%-17s%-17s\n", "Interface",
                        "    HELLO", "    DB-Desc", "   LS-Req", "   LS-Update",
@@ -1247,61 +1250,158 @@ static int ospf6_interface_show_traffic(struct vty *vty,
                        else
                                continue;
 
-                       vty_out(vty,
-                               "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u\n",
-                               oi->interface->name, oi->hello_in,
-                               oi->hello_out, oi->db_desc_in, oi->db_desc_out,
-                               oi->ls_req_in, oi->ls_req_out, oi->ls_upd_in,
-                               oi->ls_upd_out, oi->ls_ack_in, oi->ls_ack_out);
+                       if (use_json) {
+                               json_interface = json_object_new_object();
+                               json_object_int_add(json_interface, "helloRx",
+                                                   oi->hello_in);
+                               json_object_int_add(json_interface, "helloTx",
+                                                   oi->hello_out);
+                               json_object_int_add(json_interface, "dbDescRx",
+                                                   oi->db_desc_in);
+                               json_object_int_add(json_interface, "dbDescTx",
+                                                   oi->db_desc_out);
+                               json_object_int_add(json_interface, "lsReqRx",
+                                                   oi->ls_req_in);
+                               json_object_int_add(json_interface, "lsReqTx",
+                                                   oi->ls_req_out);
+                               json_object_int_add(json_interface,
+                                                   "lsUpdateRx",
+                                                   oi->ls_upd_in);
+                               json_object_int_add(json_interface,
+                                                   "lsUpdateTx",
+                                                   oi->ls_upd_out);
+                               json_object_int_add(json_interface, "lsAckRx",
+                                                   oi->ls_ack_in);
+                               json_object_int_add(json_interface, "lsAckTx",
+                                                   oi->ls_ack_out);
+
+                               json_object_object_add(json,
+                                                      oi->interface->name,
+                                                      json_interface);
+                       } else
+                               vty_out(vty,
+                                       "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u\n",
+                                       oi->interface->name, oi->hello_in,
+                                       oi->hello_out, oi->db_desc_in,
+                                       oi->db_desc_out, oi->ls_req_in,
+                                       oi->ls_req_out, oi->ls_upd_in,
+                                       oi->ls_upd_out, oi->ls_ack_in,
+                                       oi->ls_ack_out);
                }
        } else {
                oi = intf_ifp->info;
                if (oi == NULL)
                        return CMD_WARNING;
 
-               vty_out(vty,
-                       "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u\n",
-                       oi->interface->name, oi->hello_in, oi->hello_out,
-                       oi->db_desc_in, oi->db_desc_out, oi->ls_req_in,
-                       oi->ls_req_out, oi->ls_upd_in, oi->ls_upd_out,
-                       oi->ls_ack_in, oi->ls_ack_out);
+               if (use_json) {
+                       json_interface = json_object_new_object();
+                       json_object_int_add(json_interface, "helloRx",
+                                           oi->hello_in);
+                       json_object_int_add(json_interface, "helloTx",
+                                           oi->hello_out);
+                       json_object_int_add(json_interface, "dbDescRx",
+                                           oi->db_desc_in);
+                       json_object_int_add(json_interface, "dbDescTx",
+                                           oi->db_desc_out);
+                       json_object_int_add(json_interface, "lsReqRx",
+                                           oi->ls_req_in);
+                       json_object_int_add(json_interface, "lsReqTx",
+                                           oi->ls_req_out);
+                       json_object_int_add(json_interface, "lsUpdateRx",
+                                           oi->ls_upd_in);
+                       json_object_int_add(json_interface, "lsUpdateTx",
+                                           oi->ls_upd_out);
+                       json_object_int_add(json_interface, "lsAckRx",
+                                           oi->ls_ack_in);
+                       json_object_int_add(json_interface, "lsAckTx",
+                                           oi->ls_ack_out);
+
+                       json_object_object_add(json, oi->interface->name,
+                                              json_interface);
+               } else
+                       vty_out(vty,
+                               "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u\n",
+                               oi->interface->name, oi->hello_in,
+                               oi->hello_out, oi->db_desc_in, oi->db_desc_out,
+                               oi->ls_req_in, oi->ls_req_out, oi->ls_upd_in,
+                               oi->ls_upd_out, oi->ls_ack_in, oi->ls_ack_out);
        }
 
        return CMD_SUCCESS;
 }
 
 /* show interface */
-DEFUN (show_ipv6_ospf6_interface_traffic,
-       show_ipv6_ospf6_interface_traffic_cmd,
-       "show ipv6 ospf6 interface traffic [IFNAME]",
-       SHOW_STR
-       IP6_STR
-       OSPF6_STR
-       INTERFACE_STR
-       "Protocol Packet counters\n"
-       IFNAME_STR)
+DEFUN(show_ipv6_ospf6_interface_traffic,
+      show_ipv6_ospf6_interface_traffic_cmd,
+      "show ipv6 ospf6 interface traffic [IFNAME] [json]",
+      SHOW_STR
+      IP6_STR
+      OSPF6_STR
+      INTERFACE_STR
+      "Protocol Packet counters\n"
+      IFNAME_STR
+      JSON_STR)
 {
        int idx_ifname = 0;
        int display_once = 0;
        char *intf_name = NULL;
        struct interface *ifp = NULL;
+       json_object *json = NULL;
+       bool uj = use_json(argc, argv);
+
+       if (uj)
+               json = json_object_new_object();
 
        if (argv_find(argv, argc, "IFNAME", &idx_ifname)) {
                intf_name = argv[idx_ifname]->arg;
                ifp = if_lookup_by_name(intf_name, VRF_DEFAULT);
-               if (ifp == NULL) {
-                       vty_out(vty, "No such Interface: %s\n", intf_name);
-                       return CMD_WARNING;
-               }
-               if (ifp->info == NULL) {
-                       vty_out(vty,
-                               "   OSPF not enabled on this interface %s\n",
-                               intf_name);
-                       return 0;
+               if (uj) {
+                       if (ifp == NULL) {
+                               json_object_string_add(json, "status",
+                                                      "No Such Interface");
+                               json_object_string_add(json, "interface",
+                                                      intf_name);
+                               vty_out(vty, "%s\n",
+                                       json_object_to_json_string_ext(
+                                               json, JSON_C_TO_STRING_PRETTY));
+                               json_object_free(json);
+                               return CMD_WARNING;
+                       }
+                       if (ifp->info == NULL) {
+                               json_object_string_add(
+                                       json, "status",
+                                       "OSPF not enabled on this interface");
+                               json_object_string_add(json, "interface",
+                                                      intf_name);
+                               vty_out(vty, "%s\n",
+                                       json_object_to_json_string_ext(
+                                               json, JSON_C_TO_STRING_PRETTY));
+                               json_object_free(json);
+                               return 0;
+                       }
+               } else {
+                       if (ifp == NULL) {
+                               vty_out(vty, "No such Interface: %s\n",
+                                       intf_name);
+                               return CMD_WARNING;
+                       }
+                       if (ifp->info == NULL) {
+                               vty_out(vty,
+                                       "   OSPF not enabled on this interface %s\n",
+                                       intf_name);
+                               return 0;
+                       }
                }
        }
 
-       ospf6_interface_show_traffic(vty, ifp, display_once);
+       ospf6_interface_show_traffic(vty, ifp, display_once, json, uj);
+
+       if (uj) {
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
 
 
        return CMD_SUCCESS;
index f84a7cfe9af1c398400497d9e353018b75a71b53..17538c466aaaa3ea030c426932f64cf0752a4e65 100644 (file)
@@ -609,9 +609,8 @@ static char *ospf6_link_lsa_get_prefix_str(struct ospf6_lsa *lsa, char *buf,
                                return NULL;
                        }
 
-                       if (cnt < pos) {
-                               current =
-                                       start + pos * OSPF6_PREFIX_SIZE(prefix);
+                       if (cnt < (pos - 1)) {
+                               current += OSPF6_PREFIX_SIZE(prefix);
                                cnt++;
                        } else {
                                memset(&in6, 0, sizeof(in6));
@@ -796,7 +795,7 @@ static char *ospf6_intra_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa,
                                    + sizeof(struct ospf6_lsa_header));
 
                prefixnum = ntohs(intra_prefix_lsa->prefix_num);
-               if (pos > prefixnum)
+               if ((pos + 1) > prefixnum)
                        return NULL;
 
                start = (char *)intra_prefix_lsa
@@ -812,8 +811,7 @@ static char *ospf6_intra_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa,
                        }
 
                        if (cnt < pos) {
-                               current =
-                                       start + pos * OSPF6_PREFIX_SIZE(prefix);
+                               current += OSPF6_PREFIX_SIZE(prefix);
                                cnt++;
                        } else {
                                memset(&in6, 0, sizeof(in6));
@@ -987,7 +985,7 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread)
                        if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
                                zlog_debug("    include %pFX", &route->prefix);
                        ospf6_route_add(ospf6_route_copy(route),
-                                       route_advertise, oa->ospf6);
+                                       route_advertise);
                }
        }
 
@@ -1008,7 +1006,7 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread)
                                        oa->lsdb);
                        }
                }
-               ospf6_route_table_delete(route_advertise, oa->ospf6);
+               ospf6_route_table_delete(route_advertise);
                return 0;
        }
 
@@ -1088,7 +1086,7 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread)
                op = OSPF6_PREFIX_NEXT(op);
        }
 
-       ospf6_route_table_delete(route_advertise, oa->ospf6);
+       ospf6_route_table_delete(route_advertise);
 
        if (prefix_num == 0) {
                if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
@@ -1254,8 +1252,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread)
                        if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
                                zlog_debug("    include %pFX", &route->prefix);
 
-                       ospf6_route_add(route, route_advertise,
-                                       oi->area->ospf6);
+                       ospf6_route_add(route, route_advertise);
                        prefix_num--;
                }
                if (current != end && IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
@@ -1277,7 +1274,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread)
                prefix_num++;
        }
 
-       ospf6_route_table_delete(route_advertise, oi->area->ospf6);
+       ospf6_route_table_delete(route_advertise);
 
        if (prefix_num == 0) {
                if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
@@ -1438,7 +1435,7 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
                                         */
                                        if (oa->route_table->hook_add)
                                                (*oa->route_table->hook_add)(
-                                                       old_route, oa->ospf6);
+                                                       old_route);
 
                                        if (old_route->path.origin.id ==
                                        route->path.origin.id &&
@@ -1459,8 +1456,7 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
                                }
                                if (oa->route_table->hook_remove)
                                        ospf6_route_remove(old_route,
-                                                          oa->route_table,
-                                                          oa->ospf6);
+                                                          oa->route_table);
                                else
                                        SET_FLAG(old_route->flag,
                                                 OSPF6_ROUTE_REMOVE);
@@ -1601,8 +1597,7 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
                        SET_FLAG(old_route->flag, OSPF6_ROUTE_ADD);
                        /* Update ospf6 route table and RIB/FIB */
                        if (oa->route_table->hook_add)
-                               (*oa->route_table->hook_add)(old_route,
-                                                            oa->ospf6);
+                               (*oa->route_table->hook_add)(old_route);
                        /* Delete the new route its info added to existing
                         * route.
                         */
@@ -1614,7 +1609,7 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
 
        if (!route_found) {
                /* Add new route to existing node in ospf6 route table. */
-               ospf6_route_add(route, oa->route_table, oa->ospf6);
+               ospf6_route_add(route, oa->route_table);
        }
 }
 
@@ -1757,7 +1752,7 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
                                        listcount(route->paths),
                                        listcount(route->nh_list));
                        }
-                       ospf6_route_add(route, oa->route_table, oa->ospf6);
+                       ospf6_route_add(route, oa->route_table);
                }
                prefix_num--;
        }
@@ -1839,7 +1834,7 @@ static void ospf6_intra_prefix_lsa_remove_update_route(struct ospf6_lsa *lsa,
                 * nh_list
                 */
                if (oa->route_table->hook_add)
-                       (*oa->route_table->hook_add)(route, oa->ospf6);
+                       (*oa->route_table->hook_add)(route);
 
                /* route's primary path is similar
                 * to LSA, replace route's primary
@@ -1932,8 +1927,7 @@ void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa)
                                                listcount(route->paths),
                                                listcount(route->nh_list));
                                }
-                               ospf6_route_remove(route, oa->route_table,
-                                                  oa->ospf6);
+                               ospf6_route_remove(route, oa->route_table);
                        }
                }
                if (route)
@@ -1949,8 +1943,8 @@ void ospf6_intra_route_calculation(struct ospf6_area *oa)
        struct ospf6_route *route, *nroute;
        uint16_t type;
        struct ospf6_lsa *lsa;
-       void (*hook_add)(struct ospf6_route *, struct ospf6 *) = NULL;
-       void (*hook_remove)(struct ospf6_route *, struct ospf6 *) = NULL;
+       void (*hook_add)(struct ospf6_route *) = NULL;
+       void (*hook_remove)(struct ospf6_route *) = NULL;
 
        if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
                zlog_debug("Re-examin intra-routes for area %s", oa->name);
@@ -1980,11 +1974,11 @@ void ospf6_intra_route_calculation(struct ospf6_area *oa)
                }
 
                if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE))
-                       ospf6_route_remove(route, oa->route_table, oa->ospf6);
+                       ospf6_route_remove(route, oa->route_table);
                else if (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)
                         || CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE)) {
                        if (hook_add)
-                               (*hook_add)(route, oa->ospf6);
+                               (*hook_add)(route);
                        route->flag = 0;
                } else {
                        /* Redo the summaries as things might have changed */
@@ -2056,8 +2050,8 @@ static void ospf6_brouter_debug_print(struct ospf6_route *brouter)
 void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
 {
        struct ospf6_route *brouter, *nbrouter, *copy;
-       void (*hook_add)(struct ospf6_route *, struct ospf6 *) = NULL;
-       void (*hook_remove)(struct ospf6_route *, struct ospf6 *) = NULL;
+       void (*hook_add)(struct ospf6_route *) = NULL;
+       void (*hook_remove)(struct ospf6_route *) = NULL;
        uint32_t brouter_id;
        char brouter_name[16];
 
@@ -2115,7 +2109,7 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
                copy = ospf6_route_copy(brouter);
                copy->type = OSPF6_DEST_TYPE_ROUTER;
                copy->path.area_id = oa->area_id;
-               ospf6_route_add(copy, oa->ospf6->brouter_table, oa->ospf6);
+               ospf6_route_add(copy, oa->ospf6->brouter_table);
 
                if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(brouter_id)
                    || IS_OSPF6_DEBUG_ROUTE(MEMORY)) {
@@ -2201,8 +2195,7 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
                         * removes brouters which are marked for remove.
                         */
                        oa->intra_brouter_calc = 1;
-                       ospf6_route_remove(brouter, oa->ospf6->brouter_table,
-                                          oa->ospf6);
+                       ospf6_route_remove(brouter, oa->ospf6->brouter_table);
                        brouter = NULL;
                } else if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_ADD)
                           || CHECK_FLAG(brouter->flag, OSPF6_ROUTE_CHANGE)) {
@@ -2216,7 +2209,7 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
 
                        /* newly added */
                        if (hook_add)
-                               (*hook_add)(brouter, oa->ospf6);
+                               (*hook_add)(brouter);
                } else {
                        if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(
                                    brouter_id)
index 0892863cf10cae0499b4c5b5966985a60d14781b..c136c558cb7cb72f4be708332b3c1dfcd3f39031 100644 (file)
@@ -68,9 +68,9 @@ static void ospf6_lsdb_set_key(struct prefix_ipv6 *key, const void *value,
 #ifdef DEBUG
 static void _lsdb_count_assert(struct ospf6_lsdb *lsdb)
 {
-       struct ospf6_lsa *debug;
+       struct ospf6_lsa *debug, *debugnext;
        unsigned int num = 0;
-       for (ALL_LSDB(lsdb, debug))
+       for (ALL_LSDB(lsdb, debug, debugnext))
                num++;
 
        if (num == lsdb->count)
@@ -78,7 +78,7 @@ static void _lsdb_count_assert(struct ospf6_lsdb *lsdb)
 
        zlog_debug("PANIC !! lsdb[%p]->count = %d, real = %d", lsdb,
                   lsdb->count, num);
-       for (ALL_LSDB(lsdb, debug))
+       for (ALL_LSDB(lsdb, debug, debugnext))
                zlog_debug("%s lsdb[%p]", debug->name, debug->lsdb);
        zlog_debug("DUMP END");
 
index 4ed6e2a6040dbb85d932e8d43743aa7d91255870..69424f4b46cb4f9710cd0c139bc77f6b8a78101c 100644 (file)
@@ -88,12 +88,11 @@ static void __attribute__((noreturn)) ospf6_exit(int status)
 
        for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
                vrf = vrf_lookup_by_id(ospf6->vrf_id);
-               ospf6_serv_close(&ospf6->fd);
+               ospf6_delete(ospf6);
+               ospf6 = NULL;
                FOR_ALL_INTERFACES (vrf, ifp)
                        if (ifp->info != NULL)
                                ospf6_interface_delete(ifp->info);
-               ospf6_delete(ospf6);
-               ospf6 = NULL;
        }
 
        bfd_gbl_exit();
index c008b54ce7b765a3502f6b0da358f6fdfaa93df9..6585fc1580e89690861a7e398de97d6f0c7b7278 100644 (file)
@@ -44,3 +44,4 @@ DEFINE_MTYPE(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info")
 DEFINE_MTYPE(OSPF6D, OSPF6_PATH, "OSPF6 Path")
 DEFINE_MTYPE(OSPF6D, OSPF6_DIST_ARGS, "OSPF6 Distribute arguments")
 DEFINE_MTYPE(OSPF6D, OSPF6_OTHER, "OSPF6 other")
+DEFINE_MTYPE(OSPF6D, OSPF6_REDISTRIBUTE, "OSPF6 Redistribute arguments")
index a97d677543f3a189492e6e4b79d94ce89805410a..57f0abd9a848d78893c6028eb117bc442b28252d 100644 (file)
@@ -42,6 +42,7 @@ DECLARE_MTYPE(OSPF6_NEXTHOP)
 DECLARE_MTYPE(OSPF6_EXTERNAL_INFO)
 DECLARE_MTYPE(OSPF6_PATH)
 DECLARE_MTYPE(OSPF6_DIST_ARGS)
+DECLARE_MTYPE(OSPF6_REDISTRIBUTE)
 DECLARE_MTYPE(OSPF6_OTHER)
 
 #endif /* _QUAGGA_OSPF6_MEMORY_H */
index c1905e8c1eb1b6ac6f49aac08f62daef558260e0..7a1b96c2b3b8f7cb5f959be241b4d1938d7cc6b6 100644 (file)
@@ -1075,9 +1075,10 @@ DEFUN (show_ipv6_ospf6_neighbor_one,
 
        for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
                for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi))
-                       for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, on))
-                               (*showfunc)(vty, on, json, uj);
-
+                       for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, on)) {
+                               if (router_id == on->router_id)
+                                       (*showfunc)(vty, on, json, uj);
+                       }
 
        if (uj) {
                vty_out(vty, "%s\n",
index 2602854f33d8524f56525068b40373c1096c5be6..60c208437bc3ba6e3f67748d0a54676477870c8f 100644 (file)
@@ -292,28 +292,28 @@ void ospf6_add_nexthop(struct list *nh_list, int ifindex, struct in6_addr *addr)
 
 void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,
                                     struct zapi_nexthop nexthops[],
-                                    int entries)
+                                    int entries, vrf_id_t vrf_id)
 {
        struct ospf6_nexthop *nh;
        struct listnode *node;
-       struct interface *ifp;
        char buf[64];
        int i;
 
        if (route) {
                i = 0;
                for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
-                       ifp = if_lookup_by_index_all_vrf(nh->ifindex);
                        if (IS_OSPF6_DEBUG_ZEBRA(SEND)) {
+                               const char *ifname;
                                inet_ntop(AF_INET6, &nh->address, buf,
                                          sizeof(buf));
+                               ifname = ifindex2ifname(nh->ifindex, vrf_id);
                                zlog_debug("  nexthop: %s%%%.*s(%d)", buf,
-                                          IFNAMSIZ, ifp->name, nh->ifindex);
+                                          IFNAMSIZ, ifname, nh->ifindex);
                        }
                        if (i >= entries)
                                return;
 
-                       nexthops[i].vrf_id = ifp->vrf_id;
+                       nexthops[i].vrf_id = vrf_id;
                        nexthops[i].ifindex = nh->ifindex;
                        if (!IN6_IS_ADDR_UNSPECIFIED(&nh->address)) {
                                nexthops[i].gate.ipv6 = nh->address;
@@ -398,6 +398,7 @@ void ospf6_copy_paths(struct list *dst, struct list *src)
 struct ospf6_route *ospf6_route_create(void)
 {
        struct ospf6_route *route;
+
        route = XCALLOC(MTYPE_OSPF6_ROUTE, sizeof(struct ospf6_route));
        route->nh_list = list_new();
        route->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
@@ -590,8 +591,7 @@ static void route_table_assert(struct ospf6_route_table *table)
 #endif /*DEBUG*/
 
 struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
-                                   struct ospf6_route_table *table,
-                                   struct ospf6 *ospf6)
+                                   struct ospf6_route_table *table)
 {
        struct route_node *node, *nextnode, *prevnode;
        struct ospf6_route *current = NULL;
@@ -700,7 +700,7 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
                ospf6_route_table_assert(table);
 
                if (table->hook_add)
-                       (*table->hook_add)(route, ospf6);
+                       (*table->hook_add)(route);
 
                return route;
        }
@@ -755,7 +755,7 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
 
                SET_FLAG(route->flag, OSPF6_ROUTE_ADD);
                if (table->hook_add)
-                       (*table->hook_add)(route, ospf6);
+                       (*table->hook_add)(route);
 
                return route;
        }
@@ -821,13 +821,13 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
 
        SET_FLAG(route->flag, OSPF6_ROUTE_ADD);
        if (table->hook_add)
-               (*table->hook_add)(route, ospf6);
+               (*table->hook_add)(route);
 
        return route;
 }
 
 void ospf6_route_remove(struct ospf6_route *route,
-                       struct ospf6_route_table *table, struct ospf6 *ospf6)
+                       struct ospf6_route_table *table)
 {
        struct route_node *node;
        struct ospf6_route *current;
@@ -882,7 +882,7 @@ void ospf6_route_remove(struct ospf6_route *route,
 
        /* Note hook_remove may call ospf6_route_remove */
        if (table->hook_remove)
-               (*table->hook_remove)(route, ospf6);
+               (*table->hook_remove)(route);
 
        ospf6_route_unlock(route);
 }
@@ -1002,13 +1002,12 @@ struct ospf6_route *ospf6_route_match_next(struct prefix *prefix,
        return next;
 }
 
-void ospf6_route_remove_all(struct ospf6_route_table *table,
-                           struct ospf6 *ospf6)
+void ospf6_route_remove_all(struct ospf6_route_table *table)
 {
        struct ospf6_route *route;
        for (route = ospf6_route_head(table); route;
             route = ospf6_route_next(route))
-               ospf6_route_remove(route, table, ospf6);
+               ospf6_route_remove(route, table);
 }
 
 struct ospf6_route_table *ospf6_route_table_create(int s, int t)
@@ -1021,10 +1020,9 @@ struct ospf6_route_table *ospf6_route_table_create(int s, int t)
        return new;
 }
 
-void ospf6_route_table_delete(struct ospf6_route_table *table,
-                             struct ospf6 *ospf6)
+void ospf6_route_table_delete(struct ospf6_route_table *table)
 {
-       ospf6_route_remove_all(table, ospf6);
+       ospf6_route_remove_all(table);
        bf_free(table->idspace);
        route_table_finish(table->table);
        XFREE(MTYPE_OSPF6_ROUTE, table);
index 0b984400b56af36aab63c13f847d82e70b0a7b4a..e2118003d5a71f729dd76d7bc8953ec94766d66e 100644 (file)
@@ -193,9 +193,9 @@ struct ospf6_route_table {
        bitfield_t idspace;
 
        /* hooks */
-       void (*hook_add)(struct ospf6_route *, struct ospf6 *);
+       void (*hook_add)(struct ospf6_route *);
        void (*hook_change)(struct ospf6_route *);
-       void (*hook_remove)(struct ospf6_route *, struct ospf6 *);
+       void (*hook_remove)(struct ospf6_route *);
 };
 
 #define OSPF6_SCOPE_TYPE_NONE      0
@@ -280,7 +280,7 @@ extern int ospf6_route_cmp_nexthops(struct ospf6_route *a,
                                    struct ospf6_route *b);
 extern void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,
                                            struct zapi_nexthop nexthops[],
-                                           int entries);
+                                           int entries, vrf_id_t vrf_id);
 extern int ospf6_route_get_first_nh_index(struct ospf6_route *route);
 
 /* Hide abstraction of nexthop implementation in route from outsiders */
@@ -307,11 +307,9 @@ ospf6_route_lookup_bestmatch(struct prefix *prefix,
                             struct ospf6_route_table *table);
 
 extern struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
-                                          struct ospf6_route_table *table,
-                                          struct ospf6 *ospf6);
+                                          struct ospf6_route_table *table);
 extern void ospf6_route_remove(struct ospf6_route *route,
-                              struct ospf6_route_table *table,
-                              struct ospf6 *ospf6);
+                              struct ospf6_route_table *table);
 
 extern struct ospf6_route *ospf6_route_head(struct ospf6_route_table *table);
 extern struct ospf6_route *ospf6_route_next(struct ospf6_route *route);
@@ -322,10 +320,9 @@ ospf6_route_match_head(struct prefix *prefix, struct ospf6_route_table *table);
 extern struct ospf6_route *ospf6_route_match_next(struct prefix *prefix,
                                                  struct ospf6_route *route);
 
-extern void ospf6_route_remove_all(struct ospf6_route_table *, struct ospf6 *);
+extern void ospf6_route_remove_all(struct ospf6_route_table *table);
 extern struct ospf6_route_table *ospf6_route_table_create(int s, int t);
-extern void ospf6_route_table_delete(struct ospf6_route_table *,
-                                    struct ospf6 *);
+extern void ospf6_route_table_delete(struct ospf6_route_table *table);
 extern void ospf6_route_dump(struct ospf6_route_table *table);
 
 
index 3aeba3b6096b36628e356312a0554b9792f8a78a..51a3bff2a38685ccf83418a60a19d09a343b7c09 100644 (file)
@@ -963,8 +963,6 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length,
                else if (v->magic & OSPFv3WWLINKTABLE) {
                        /* We build a sorted list of interfaces */
                        ifslist = list_new();
-                       if (!ifslist)
-                               return NULL;
                        ifslist->cmp = (int (*)(void *, void *))if_icmp_func;
                        FOR_ALL_INTERFACES (vrf, iif)
                                listnode_add_sort(ifslist, iif);
@@ -993,6 +991,7 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length,
                        }
 
                        list_delete_all_node(ifslist);
+                       list_delete(&ifslist);
                }
        }
 
@@ -1100,8 +1099,6 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,
        } else {
                /* We build a sorted list of interfaces */
                ifslist = list_new();
-               if (!ifslist)
-                       return NULL;
                ifslist->cmp = (int (*)(void *, void *))if_icmp_func;
                FOR_ALL_INTERFACES (vrf, iif)
                        listnode_add_sort(ifslist, iif);
@@ -1121,6 +1118,7 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,
                }
 
                list_delete_all_node(ifslist);
+               list_delete(&ifslist);
        }
 
        if (!oi)
@@ -1267,8 +1265,6 @@ static uint8_t *ospfv3NbrEntry(struct variable *v, oid *name, size_t *length,
        } else {
                /* We build a sorted list of interfaces */
                ifslist = list_new();
-               if (!ifslist)
-                       return NULL;
                ifslist->cmp = (int (*)(void *, void *))if_icmp_func;
                FOR_ALL_INTERFACES (vrf, iif)
                        listnode_add_sort(ifslist, iif);
@@ -1296,6 +1292,7 @@ static uint8_t *ospfv3NbrEntry(struct variable *v, oid *name, size_t *length,
                }
 
                list_delete_all_node(ifslist);
+               list_delete(&ifslist);
        }
 
        if (!oi || !on)
index 4dd1d5a462e4ad88101491779ccec018a2db49a5..70771c6060f9359511fb50c99eb9b6ca63d42f31 100644 (file)
@@ -316,8 +316,7 @@ static void ospf6_nexthop_calc(struct ospf6_vertex *w, struct ospf6_vertex *v,
 }
 
 static int ospf6_spf_install(struct ospf6_vertex *v,
-                            struct ospf6_route_table *result_table,
-                            struct ospf6 *ospf6)
+                            struct ospf6_route_table *result_table)
 {
        struct ospf6_route *route, *parent_route;
        struct ospf6_vertex *prev;
@@ -417,12 +416,11 @@ static int ospf6_spf_install(struct ospf6_vertex *v,
                listnode_add_sort(v->parent->child_list, v);
        route->route_option = v;
 
-       ospf6_route_add(route, result_table, ospf6);
+       ospf6_route_add(route, result_table);
        return 0;
 }
 
-void ospf6_spf_table_finish(struct ospf6_route_table *result_table,
-                           struct ospf6 *ospf6)
+void ospf6_spf_table_finish(struct ospf6_route_table *result_table)
 {
        struct ospf6_route *route, *nroute;
        struct ospf6_vertex *v;
@@ -430,7 +428,7 @@ void ospf6_spf_table_finish(struct ospf6_route_table *result_table,
                nroute = ospf6_route_next(route);
                v = (struct ospf6_vertex *)route->route_option;
                ospf6_vertex_delete(v);
-               ospf6_route_remove(route, result_table, ospf6);
+               ospf6_route_remove(route, result_table);
        }
 }
 
@@ -468,7 +466,7 @@ void ospf6_spf_calculation(uint32_t router_id,
        struct ospf6_lsa *lsa;
        struct in6_addr address;
 
-       ospf6_spf_table_finish(result_table, oa->ospf6);
+       ospf6_spf_table_finish(result_table);
 
        /* Install the calculating router itself as the root of the SPF tree */
        /* construct root vertex */
@@ -497,7 +495,7 @@ void ospf6_spf_calculation(uint32_t router_id,
        while ((v = vertex_pqueue_pop(&candidate_list))) {
                /* installing may result in merging or rejecting of the vertex
                 */
-               if (ospf6_spf_install(v, result_table, oa->ospf6) < 0)
+               if (ospf6_spf_install(v, result_table) < 0)
                        continue;
 
                /* Skip overloaded routers */
index f288f91f57c812fe6d507dc046ffe93be478b20d..853ce4de07db1a6ca43cdd35878749a0803684bf 100644 (file)
@@ -139,8 +139,7 @@ static inline unsigned int ospf6_lsremove_to_spf_reason(struct ospf6_lsa *lsa)
        return (reason);
 }
 
-extern void ospf6_spf_table_finish(struct ospf6_route_table *result_table,
-                                  struct ospf6 *ospf6);
+extern void ospf6_spf_table_finish(struct ospf6_route_table *result_table);
 extern void ospf6_spf_calculation(uint32_t router_id,
                                  struct ospf6_route_table *result_table,
                                  struct ospf6_area *oa);
index 95c72290d0ce24a3f89bb03ff69002c0eec55603..7b4ed84d53849cf160e4fbd006c1525dfa739fb4 100644 (file)
@@ -29,6 +29,7 @@
 #include "thread.h"
 #include "command.h"
 #include "defaults.h"
+#include "lib/json.h"
 #include "lib_errors.h"
 
 #include "ospf6_proto.h"
@@ -123,12 +124,9 @@ struct ospf6 *ospf6_lookup_by_vrf_name(const char *name)
 
 static void ospf6_top_lsdb_hook_add(struct ospf6_lsa *lsa)
 {
-       struct ospf6 *ospf6 = NULL;
-
        switch (ntohs(lsa->header->type)) {
        case OSPF6_LSTYPE_AS_EXTERNAL:
-               ospf6 = ospf6_get_by_lsdb(lsa);
-               ospf6_asbr_lsa_add(lsa, ospf6);
+               ospf6_asbr_lsa_add(lsa);
                break;
 
        default:
@@ -148,24 +146,27 @@ static void ospf6_top_lsdb_hook_remove(struct ospf6_lsa *lsa)
        }
 }
 
-static void ospf6_top_route_hook_add(struct ospf6_route *route,
-                                    struct ospf6 *ospf6)
+static void ospf6_top_route_hook_add(struct ospf6_route *route)
 {
+       struct ospf6 *ospf6 = route->table->scope;
+
        ospf6_abr_originate_summary(route, ospf6);
        ospf6_zebra_route_update_add(route, ospf6);
 }
 
-static void ospf6_top_route_hook_remove(struct ospf6_route *route,
-                                       struct ospf6 *ospf6)
+static void ospf6_top_route_hook_remove(struct ospf6_route *route)
 {
+       struct ospf6 *ospf6 = route->table->scope;
+
        route->flag |= OSPF6_ROUTE_REMOVE;
        ospf6_abr_originate_summary(route, ospf6);
        ospf6_zebra_route_update_remove(route, ospf6);
 }
 
-static void ospf6_top_brouter_hook_add(struct ospf6_route *route,
-                                      struct ospf6 *ospf6)
+static void ospf6_top_brouter_hook_add(struct ospf6_route *route)
 {
+       struct ospf6 *ospf6 = route->table->scope;
+
        if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) ||
            IS_OSPF6_DEBUG_BROUTER) {
                uint32_t brouter_id;
@@ -185,9 +186,10 @@ static void ospf6_top_brouter_hook_add(struct ospf6_route *route,
        ospf6_abr_originate_summary(route, ospf6);
 }
 
-static void ospf6_top_brouter_hook_remove(struct ospf6_route *route,
-                                         struct ospf6 *ospf6)
+static void ospf6_top_brouter_hook_remove(struct ospf6_route *route)
 {
+       struct ospf6 *ospf6 = route->table->scope;
+
        if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) ||
            IS_OSPF6_DEBUG_BROUTER) {
                uint32_t brouter_id;
@@ -300,6 +302,8 @@ void ospf6_delete(struct ospf6 *o)
        ospf6_disable(o);
        ospf6_del(o);
 
+       ospf6_serv_close(&o->fd);
+
        for (ALL_LIST_ELEMENTS(o->area_list, node, nnode, oa))
                ospf6_area_delete(oa);
 
@@ -309,10 +313,10 @@ void ospf6_delete(struct ospf6 *o)
        ospf6_lsdb_delete(o->lsdb);
        ospf6_lsdb_delete(o->lsdb_self);
 
-       ospf6_route_table_delete(o->route_table, o);
-       ospf6_route_table_delete(o->brouter_table, o);
+       ospf6_route_table_delete(o->route_table);
+       ospf6_route_table_delete(o->brouter_table);
 
-       ospf6_route_table_delete(o->external_table, o);
+       ospf6_route_table_delete(o->external_table);
        route_table_finish(o->external_id_table);
 
        ospf6_distance_reset(o);
@@ -334,11 +338,12 @@ static void ospf6_disable(struct ospf6 *o)
                        ospf6_area_disable(oa);
 
                /* XXX: This also changes persistent settings */
-               ospf6_asbr_redistribute_reset(o->vrf_id);
+               /* Unregister redistribution */
+               ospf6_asbr_redistribute_reset(o);
 
                ospf6_lsdb_remove_all(o->lsdb);
-               ospf6_route_remove_all(o->route_table, o);
-               ospf6_route_remove_all(o->brouter_table, o);
+               ospf6_route_remove_all(o->route_table);
+               ospf6_route_remove_all(o->brouter_table);
 
                THREAD_OFF(o->maxage_remover);
                THREAD_OFF(o->t_spf_calc);
@@ -456,7 +461,6 @@ DEFUN (no_router_ospf6,
        if (ospf6 == NULL)
                vty_out(vty, "OSPFv3 is not configured\n");
        else {
-               ospf6_serv_close(&ospf6->fd);
                ospf6_delete(ospf6);
                ospf6 = NULL;
        }
@@ -845,7 +849,7 @@ DEFUN (no_ospf6_interface_area,
                return CMD_SUCCESS;
        }
 
-       thread_execute(master, interface_down, oi, 0);
+       ospf6_interface_disable(oi);
 
        oa = oi->area;
        listnode_delete(oi->area->if_list, oi);
@@ -856,6 +860,7 @@ DEFUN (no_ospf6_interface_area,
                UNSET_FLAG(oa->flag, OSPF6_AREA_ENABLE);
                ospf6_abr_disable_area(oa);
        }
+       ospf6_interface_delete(oi);
 
        return CMD_SUCCESS;
 }
@@ -954,90 +959,207 @@ DEFUN (no_ospf6_stub_router_shutdown,
 }
 #endif
 
-static void ospf6_show(struct vty *vty, struct ospf6 *o)
+
+static void ospf6_show(struct vty *vty, struct ospf6 *o, json_object *json,
+                      bool use_json)
 {
        struct listnode *n;
        struct ospf6_area *oa;
        char router_id[16], duration[32];
        struct timeval now, running, result;
        char buf[32], rbuf[32];
+       json_object *json_areas = NULL;
+       const char *adjacency;
+
+       if (use_json) {
+               json_areas = json_object_new_object();
+
+               /* process id, router id */
+               inet_ntop(AF_INET, &o->router_id, router_id, sizeof(router_id));
+               json_object_string_add(json, "routerId", router_id);
+
+               /* running time */
+               monotime(&now);
+               timersub(&now, &o->starttime, &running);
+               timerstring(&running, duration, sizeof(duration));
+               json_object_string_add(json, "running", duration);
+
+               /* Redistribute configuration */
+               /* XXX */
+               json_object_int_add(json, "lsaMinimumArrivalMsecs",
+                                   o->lsa_minarrival);
+
+               /* Show SPF parameters */
+               json_object_int_add(json, "spfScheduleDelayMsecs",
+                                   o->spf_delay);
+               json_object_int_add(json, "holdTimeMinMsecs", o->spf_holdtime);
+               json_object_int_add(json, "holdTimeMaxMsecs",
+                                   o->spf_max_holdtime);
+               json_object_int_add(json, "holdTimeMultiplier",
+                                   o->spf_hold_multiplier);
+
+
+               if (o->ts_spf.tv_sec || o->ts_spf.tv_usec) {
+                       timersub(&now, &o->ts_spf, &result);
+                       timerstring(&result, buf, sizeof(buf));
+                       ospf6_spf_reason_string(o->last_spf_reason, rbuf,
+                                               sizeof(rbuf));
+                       json_object_boolean_true_add(json, "spfHasRun");
+                       json_object_string_add(json, "spfLastExecutedMsecs",
+                                              buf);
+                       json_object_string_add(json, "spfLastExecutedReason",
+                                              rbuf);
+
+                       json_object_int_add(
+                               json, "spfLastDurationSecs",
+                               (long long)o->ts_spf_duration.tv_sec);
+
+                       json_object_int_add(
+                               json, "spfLastDurationMsecs",
+                               (long long)o->ts_spf_duration.tv_usec);
+               } else
+                       json_object_boolean_false_add(json, "spfHasRun");
+
+
+               threadtimer_string(now, o->t_spf_calc, buf, sizeof(buf));
+               if (o->t_spf_calc) {
+                       long time_store;
+
+                       json_object_boolean_true_add(json, "spfTimerActive");
+                       time_store =
+                               monotime_until(&o->t_spf_calc->u.sands, NULL)
+                               / 1000LL;
+                       json_object_int_add(json, "spfTimerDueInMsecs",
+                                           time_store);
+               } else
+                       json_object_boolean_false_add(json, "spfTimerActive");
+
+               json_object_boolean_add(json, "routerIsStubRouter",
+                                       CHECK_FLAG(o->flag, OSPF6_STUB_ROUTER));
+
+               /* LSAs */
+               json_object_int_add(json, "numberOfAsScopedLsa",
+                                   o->lsdb->count);
+               /* Areas */
+               json_object_int_add(json, "numberOfAreaInRouter",
+                                   listcount(o->area_list));
+
+               if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) {
+                       if (CHECK_FLAG(o->config_flags,
+                                      OSPF6_LOG_ADJACENCY_DETAIL))
+                               adjacency = "LoggedAll";
+                       else
+                               adjacency = "Logged";
+               } else
+                       adjacency = "NotLogged";
+               json_object_string_add(json, "adjacencyChanges", adjacency);
+
+               for (ALL_LIST_ELEMENTS_RO(o->area_list, n, oa))
+                       ospf6_area_show(vty, oa, json_areas, use_json);
+
+               json_object_object_add(json, "areas", json_areas);
+
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+
+       } else {
+               /* process id, router id */
+               inet_ntop(AF_INET, &o->router_id, router_id, sizeof(router_id));
+               vty_out(vty, " OSPFv3 Routing Process (0) with Router-ID %s\n",
+                       router_id);
+
+               /* running time */
+               monotime(&now);
+               timersub(&now, &o->starttime, &running);
+               timerstring(&running, duration, sizeof(duration));
+               vty_out(vty, " Running %s\n", duration);
+
+               /* Redistribute configuration */
+               /* XXX */
+               vty_out(vty, " LSA minimum arrival %d msecs\n",
+                       o->lsa_minarrival);
+
+
+               /* Show SPF parameters */
+               vty_out(vty,
+                       " Initial SPF scheduling delay %d millisec(s)\n"
+                       " Minimum hold time between consecutive SPFs %d millsecond(s)\n"
+                       " Maximum hold time between consecutive SPFs %d millsecond(s)\n"
+                       " Hold time multiplier is currently %d\n",
+                       o->spf_delay, o->spf_holdtime, o->spf_max_holdtime,
+                       o->spf_hold_multiplier);
+
+
+               vty_out(vty, " SPF algorithm ");
+               if (o->ts_spf.tv_sec || o->ts_spf.tv_usec) {
+                       timersub(&now, &o->ts_spf, &result);
+                       timerstring(&result, buf, sizeof(buf));
+                       ospf6_spf_reason_string(o->last_spf_reason, rbuf,
+                                               sizeof(rbuf));
+                       vty_out(vty, "last executed %s ago, reason %s\n", buf,
+                               rbuf);
+                       vty_out(vty, " Last SPF duration %lld sec %lld usec\n",
+                               (long long)o->ts_spf_duration.tv_sec,
+                               (long long)o->ts_spf_duration.tv_usec);
+               } else
+                       vty_out(vty, "has not been run\n");
+
+               threadtimer_string(now, o->t_spf_calc, buf, sizeof(buf));
+               vty_out(vty, " SPF timer %s%s\n",
+                       (o->t_spf_calc ? "due in " : "is "), buf);
+
+               if (CHECK_FLAG(o->flag, OSPF6_STUB_ROUTER))
+                       vty_out(vty, " Router Is Stub Router\n");
+
+               /* LSAs */
+               vty_out(vty, " Number of AS scoped LSAs is %u\n",
+                       o->lsdb->count);
+
+               /* Areas */
+               vty_out(vty, " Number of areas in this router is %u\n",
+                       listcount(o->area_list));
+
+               if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) {
+                       if (CHECK_FLAG(o->config_flags,
+                                      OSPF6_LOG_ADJACENCY_DETAIL))
+                               vty_out(vty,
+                                       " All adjacency changes are logged\n");
+                       else
+                               vty_out(vty, " Adjacency changes are logged\n");
+               }
 
-       /* process id, router id */
-       inet_ntop(AF_INET, &o->router_id, router_id, sizeof(router_id));
-       vty_out(vty, " OSPFv3 Routing Process (0) with Router-ID %s\n",
-               router_id);
-
-       /* running time */
-       monotime(&now);
-       timersub(&now, &o->starttime, &running);
-       timerstring(&running, duration, sizeof(duration));
-       vty_out(vty, " Running %s\n", duration);
-
-       /* Redistribute configuration */
-       /* XXX */
-
-       vty_out(vty, " LSA minimum arrival %d msecs\n", o->lsa_minarrival);
-
-       /* Show SPF parameters */
-       vty_out(vty,
-               " Initial SPF scheduling delay %d millisec(s)\n"
-               " Minimum hold time between consecutive SPFs %d millsecond(s)\n"
-               " Maximum hold time between consecutive SPFs %d millsecond(s)\n"
-               " Hold time multiplier is currently %d\n",
-               o->spf_delay, o->spf_holdtime, o->spf_max_holdtime,
-               o->spf_hold_multiplier);
-
-       vty_out(vty, " SPF algorithm ");
-       if (o->ts_spf.tv_sec || o->ts_spf.tv_usec) {
-               timersub(&now, &o->ts_spf, &result);
-               timerstring(&result, buf, sizeof(buf));
-               ospf6_spf_reason_string(o->last_spf_reason, rbuf, sizeof(rbuf));
-               vty_out(vty, "last executed %s ago, reason %s\n", buf, rbuf);
-               vty_out(vty, " Last SPF duration %lld sec %lld usec\n",
-                       (long long)o->ts_spf_duration.tv_sec,
-                       (long long)o->ts_spf_duration.tv_usec);
-       } else
-               vty_out(vty, "has not been run\n");
-       threadtimer_string(now, o->t_spf_calc, buf, sizeof(buf));
-       vty_out(vty, " SPF timer %s%s\n", (o->t_spf_calc ? "due in " : "is "),
-               buf);
-
-       if (CHECK_FLAG(o->flag, OSPF6_STUB_ROUTER))
-               vty_out(vty, " Router Is Stub Router\n");
-
-       /* LSAs */
-       vty_out(vty, " Number of AS scoped LSAs is %u\n", o->lsdb->count);
-
-       /* Areas */
-       vty_out(vty, " Number of areas in this router is %u\n",
-               listcount(o->area_list));
-
-       if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) {
-               if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_DETAIL))
-                       vty_out(vty, " All adjacency changes are logged\n");
-               else
-                       vty_out(vty, " Adjacency changes are logged\n");
-       }
 
-       vty_out(vty, "\n");
+               vty_out(vty, "\n");
 
-       for (ALL_LIST_ELEMENTS_RO(o->area_list, n, oa))
-               ospf6_area_show(vty, oa);
+               for (ALL_LIST_ELEMENTS_RO(o->area_list, n, oa))
+                       ospf6_area_show(vty, oa, json_areas, use_json);
+       }
 }
 
 /* show top level structures */
-DEFUN (show_ipv6_ospf6,
-       show_ipv6_ospf6_cmd,
-       "show ipv6 ospf6",
-       SHOW_STR
-       IP6_STR
-       OSPF6_STR)
+DEFUN(show_ipv6_ospf6,
+      show_ipv6_ospf6_cmd,
+      "show ipv6 ospf6 [json]",
+      SHOW_STR
+      IP6_STR
+      OSPF6_STR
+      JSON_STR)
 {
        struct ospf6 *ospf6;
+       bool uj = use_json(argc, argv);
+       json_object *json = NULL;
 
        ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
        OSPF6_CMD_CHECK_RUNNING(ospf6);
-       ospf6_show(vty, ospf6);
+
+       if (uj)
+               json = json_object_new_object();
+
+       ospf6_show(vty, ospf6, json, uj);
+
+       if (uj)
+               json_object_free(json);
        return CMD_SUCCESS;
 }
 
index 52e1d7ee2b847d8207ad65e2fc5955593456cb72..93e25d75995688c09f4f27e0036b7dccba6a76ab 100644 (file)
@@ -38,6 +38,17 @@ enum {
        OSPF6_LOG_ADJACENCY_DETAIL =    (1 << 1),
 };
 
+struct ospf6_redist {
+       uint8_t instance;
+       /* For redistribute route map. */
+       struct {
+               char *name;
+               struct route_map *map;
+       } route_map;
+#define ROUTEMAP_NAME(R) (R->route_map.name)
+#define ROUTEMAP(R) (R->route_map.map)
+};
+
 /* OSPFv3 top level data structure */
 struct ospf6 {
        /* The relevant vrf_id */
@@ -71,11 +82,8 @@ struct ospf6 {
        struct route_table *external_id_table;
        uint32_t external_id;
 
-       /* redistribute route-map */
-       struct {
-               char *name;
-               struct route_map *map;
-       } rmap[ZEBRA_ROUTE_MAX];
+       /* OSPF6 redistribute configuration */
+       struct list *redist[ZEBRA_ROUTE_MAX];
 
        uint8_t flag;
 
index 8d3ee1ad023eea1b226d5ea8c8fd5bca51187552..7a8027a37fab8b8e8928ff412dd932015a0f4392 100644 (file)
@@ -344,7 +344,8 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request,
        api.prefix = *dest;
        SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
        api.nexthop_num = MIN(nhcount, MULTIPATH_NUM);
-       ospf6_route_zebra_copy_nexthops(request, api.nexthops, api.nexthop_num);
+       ospf6_route_zebra_copy_nexthops(request, api.nexthops, api.nexthop_num,
+                                       api.vrf_id);
        SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
        api.metric = (request->path.metric_type == 2 ? request->path.u.cost_e2
                                                     : request->path.cost);
@@ -362,7 +363,7 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request,
        else
                ret = zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
 
-       if (ret < 0)
+       if (ret == ZCLIENT_SEND_FAILURE)
                flog_err(EC_LIB_ZAPI_SOCKET,
                         "zclient_route_send() %s failed: %s",
                         (type == REM ? "delete" : "add"),
index fe519d0a26caffc97e881fa53ba51996251d9011..4b958e550f80c684317be72474c6469e9d563933 100644 (file)
@@ -1237,8 +1237,6 @@ static void ospf6_plist_del(struct prefix_list *plist)
 /* Install ospf related commands. */
 void ospf6_init(struct thread_master *master)
 {
-       struct ospf6 *ospf6;
-
        ospf6_top_init();
        ospf6_area_init();
        ospf6_interface_init();
@@ -1302,8 +1300,4 @@ void ospf6_init(struct thread_master *master)
                VIEW_NODE,
                &show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd);
        install_element(VIEW_NODE, &show_ipv6_ospf6_database_aggr_router_cmd);
-
-       ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
-       if (ospf6 == NULL)
-               ospf6_instance_create(VRF_DEFAULT_NAME);
 }
index 634418ec5ae5b4adca264c5cd7f4177265595227..f3c4798906ca0b912c9d5051cc4579c5324797d3 100644 (file)
@@ -379,7 +379,7 @@ static int ospf_abr_nssa_am_elected(struct ospf_area *area)
 /* Check NSSA ABR status
  * assumes there are nssa areas
  */
-static void ospf_abr_nssa_check_status(struct ospf *ospf)
+void ospf_abr_nssa_check_status(struct ospf *ospf)
 {
        struct ospf_area *area;
        struct listnode *lnode, *nnode;
index b3007622c4e1b8f869c179ae786785fd3a3c8bc3..e15f4a6bf7b7b0f76f981e02b57b74ebffe1b0df 100644 (file)
@@ -83,4 +83,5 @@ extern void ospf_schedule_abr_task(struct ospf *);
 
 extern void ospf_abr_announce_network_to_area(struct prefix_ipv4 *, uint32_t,
                                              struct ospf_area *);
+extern void ospf_abr_nssa_check_status(struct ospf *ospf);
 #endif /* _ZEBRA_OSPF_ABR_H */
index 3606efc76f1090916497b571448e9165b33385b8..e18d8ddb31d0f20e455a3a68b0366e80b9f56957 100644 (file)
@@ -136,7 +136,7 @@ static void ospf_ase_complete_direct_routes(struct ospf_route *ro,
        struct ospf_path *op;
 
        for (ALL_LIST_ELEMENTS_RO(ro->paths, node, op))
-               if (op->nexthop.s_addr == 0)
+               if (op->nexthop.s_addr == INADDR_ANY)
                        op->nexthop.s_addr = nexthop.s_addr;
 }
 
@@ -191,7 +191,7 @@ ospf_ase_calculate_asbr_route (struct ospf *ospf,
       return NULL;
     }
 
-  if (al->e[0].fwd_addr.s_addr != 0)
+  if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
     {
       if (IS_DEBUG_OSPF (lsa, LSA))
        zlog_debug ("ospf_ase_calculate(): Forwarding address is not 0.0.0.0.");
@@ -748,8 +748,13 @@ void ospf_ase_unregister_external_lsa(struct ospf_lsa *lsa, struct ospf *top)
 
        if (rn) {
                lst = rn->info;
-               listnode_delete(lst, lsa);
-               ospf_lsa_unlock(&lsa); /* external_lsas list */
+               struct listnode *node = listnode_lookup(lst, lsa);
+               /* Unlock lsa only if node is present in the list */
+               if (node) {
+                       listnode_delete(lst, lsa);
+                       ospf_lsa_unlock(&lsa); /* external_lsas list */
+               }
+
                route_unlock_node(rn);
        }
 }
index e461345fe5400b29388e2ab4b7faf2437fd435fc..51599ccc8a350f5a9ef5a779e2e90b3816b3252b 100644 (file)
@@ -647,13 +647,9 @@ void ospf_if_update_params(struct interface *ifp, struct in_addr addr)
 int ospf_if_new_hook(struct interface *ifp)
 {
        int rc = 0;
-       struct ospf_if_info *oii;
 
        ifp->info = XCALLOC(MTYPE_OSPF_IF_INFO, sizeof(struct ospf_if_info));
 
-       oii = ifp->info;
-       oii->curr_mtu = ifp->mtu;
-
        IF_OIFS(ifp) = route_table_init();
        IF_OIFS_PARAMS(ifp) = route_table_init();
 
@@ -1280,6 +1276,7 @@ static int ospf_ifp_create(struct interface *ifp)
        struct ospf_if_params *params;
        struct route_node *rn;
        uint32_t count = 0;
+       struct ospf_if_info *oii;
 
        if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
                zlog_debug(
@@ -1291,6 +1288,9 @@ static int ospf_ifp_create(struct interface *ifp)
 
        assert(ifp->info);
 
+       oii = ifp->info;
+       oii->curr_mtu = ifp->mtu;
+
        if (IF_DEF_PARAMS(ifp)
            && !OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(ifp), type)) {
                SET_IF_PARAM(IF_DEF_PARAMS(ifp), type);
index 68792ebcc2e7a1ffddd41bce0f13e83737f2a63a..b574e2cac86c3d830e38e81b5eacfc3ae5f42476 100644 (file)
@@ -93,57 +93,11 @@ int ospf_ldp_sync_announce_update(struct ldp_igp_sync_announce announce)
        /* LDP just started up:
         *  set cost to LSInfinity
         *  send request to LDP for LDP-SYNC state for each interface
-        *  start hello timer
         */
        vrf = vrf_lookup_by_id(ospf->vrf_id);
        FOR_ALL_INTERFACES (vrf, ifp)
                ospf_ldp_sync_if_start(ifp, true);
 
-       THREAD_OFF(ospf->ldp_sync_cmd.t_hello);
-       ospf->ldp_sync_cmd.sequence = 0;
-       ospf_ldp_sync_hello_timer_add(ospf);
-
-       return 0;
-}
-
-int ospf_ldp_sync_hello_update(struct ldp_igp_sync_hello hello)
-{
-       struct ospf *ospf;
-       struct vrf *vrf;
-       struct interface *ifp;
-
-       /* if ospf is not enabled or LDP-SYNC is not configured ignore */
-       ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
-       if (ospf == NULL ||
-           !CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
-               return 0;
-
-       if (hello.proto != ZEBRA_ROUTE_LDP)
-               return 0;
-
-       /* Received Hello from LDP:
-        *  if current sequence number is greater than received hello
-        *  sequence number then assume LDP restarted
-        *  set cost to LSInfinity
-        *  send request to LDP for LDP-SYNC state for each interface
-        *  else all is fine just restart hello timer
-        */
-       if (hello.sequence == 0)
-               /* rolled over */
-               ospf->ldp_sync_cmd.sequence = 0;
-
-       if (ospf->ldp_sync_cmd.sequence > hello.sequence) {
-               zlog_err("ldp_sync: LDP restarted");
-
-               vrf = vrf_lookup_by_id(ospf->vrf_id);
-               FOR_ALL_INTERFACES (vrf, ifp)
-                       ospf_ldp_sync_if_start(ifp, true);
-       } else {
-               THREAD_OFF(ospf->ldp_sync_cmd.t_hello);
-               ospf_ldp_sync_hello_timer_add(ospf);
-       }
-       ospf->ldp_sync_cmd.sequence = hello.sequence;
-
        return 0;
 }
 
@@ -253,6 +207,33 @@ void ospf_ldp_sync_if_complete(struct interface *ifp)
        }
 }
 
+void ospf_ldp_sync_handle_client_close(struct zapi_client_close_info *info)
+{
+       struct ospf *ospf;
+       struct vrf *vrf;
+       struct interface *ifp;
+
+       /* if ospf is not enabled or LDP-SYNC is not configured ignore */
+       ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+       if (ospf == NULL
+           || !CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+               return;
+
+       /* Check if the LDP main client session closed */
+       if (info->proto != ZEBRA_ROUTE_LDP || info->session_id == 0)
+               return;
+
+       /* Handle the zebra notification that the LDP client session closed.
+        *  set cost to LSInfinity
+        *  send request to LDP for LDP-SYNC state for each interface
+        */
+       zlog_err("ldp_sync: LDP down");
+
+       vrf = vrf_lookup_by_id(ospf->vrf_id);
+       FOR_ALL_INTERFACES (vrf, ifp)
+               ospf_ldp_sync_ldp_fail(ifp);
+}
+
 void ospf_ldp_sync_ldp_fail(struct interface *ifp)
 {
        struct ospf_if_params *params;
@@ -264,7 +245,7 @@ void ospf_ldp_sync_ldp_fail(struct interface *ifp)
        params = IF_DEF_PARAMS(ifp);
        ldp_sync_info = params->ldp_sync_info;
 
-       /* LDP failed to send hello:
+       /* LDP client close detected:
         *  stop holddown timer
         *  set cost of interface to LSInfinity so traffic will use different
         *  interface until LDP has learned all labels from peer
@@ -420,46 +401,6 @@ void ospf_ldp_sync_holddown_timer_add(struct interface *ifp)
                         &ldp_sync_info->t_holddown);
 }
 
-/*
- * LDP-SYNC hello timer routines
- */
-static int ospf_ldp_sync_hello_timer(struct thread *thread)
-{
-       struct ospf *ospf;
-       struct vrf *vrf;
-       struct interface *ifp;
-
-       /* hello timer expired:
-        *  didn't receive hello msg from LDP
-        *  set cost of all interfaces to LSInfinity
-        */
-       ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
-       if (ospf) {
-               vrf = vrf_lookup_by_id(ospf->vrf_id);
-
-               FOR_ALL_INTERFACES (vrf, ifp)
-                       ospf_ldp_sync_ldp_fail(ifp);
-
-               zlog_err("ldp_sync: hello timer expired, LDP down");
-       }
-       return 0;
-}
-
-void ospf_ldp_sync_hello_timer_add(struct ospf *ospf)
-{
-
-       /* Start hello timer:
-        *  this timer is used to make sure LDP is up
-        *  if expires set interface cost to LSInfinity
-        */
-       if (!CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
-               return;
-
-       thread_add_timer(master, ospf_ldp_sync_hello_timer,
-                        NULL, LDP_IGP_SYNC_HELLO_TIMEOUT,
-                        &ospf->ldp_sync_cmd.t_hello);
-}
-
 /*
  * LDP-SYNC exit routes.
  */
@@ -469,7 +410,6 @@ void ospf_ldp_sync_gbl_exit(struct ospf *ospf, bool remove)
        struct vrf *vrf;
 
        /* ospf is being removed
-        *  stop hello timer
         *  stop any holddown timers
         */
        if (CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
@@ -478,15 +418,12 @@ void ospf_ldp_sync_gbl_exit(struct ospf *ospf, bool remove)
                                          LDP_IGP_SYNC_IF_STATE_UPDATE);
                zclient_unregister_opaque(zclient,
                                          LDP_IGP_SYNC_ANNOUNCE_UPDATE);
-               zclient_unregister_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE);
 
                /* disable LDP globally */
                UNSET_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
                UNSET_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
                ospf->ldp_sync_cmd.holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
 
-               THREAD_OFF(ospf->ldp_sync_cmd.t_hello);
-
                /* turn off LDP-IGP Sync on all OSPF interfaces */
                vrf = vrf_lookup_by_id(ospf->vrf_id);
                FOR_ALL_INTERFACES (vrf, ifp)
@@ -829,7 +766,6 @@ DEFPY (ospf_mpls_ldp_sync,
        /* register with opaque client to recv LDP-IGP Sync msgs */
        zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
        zclient_register_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
-       zclient_register_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE);
 
        if (!CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
                SET_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
index d4efa55311d83e7447a505289f301ac5f5ba2bd2..63f370724d40e289aa73810732be8799d8dd2425 100644 (file)
@@ -40,7 +40,6 @@ extern void ospf_ldp_sync_if_remove(struct interface *ifp, bool remove);
 extern void ospf_ldp_sync_if_down(struct interface *ifp);
 extern void ospf_ldp_sync_if_complete(struct interface *ifp);
 extern void ospf_ldp_sync_holddown_timer_add(struct interface *ifp);
-extern void ospf_ldp_sync_hello_timer_add(struct ospf *ospf);
 extern void ospf_ldp_sync_ldp_fail(struct interface *ifp);
 extern void ospf_ldp_sync_show_info(struct vty *vty, struct ospf *ospf,
                                    json_object *json_vrf, bool use_json);
@@ -49,7 +48,8 @@ extern void ospf_ldp_sync_if_write_config(struct vty *vty,
                                          struct ospf_if_params *params);
 extern int ospf_ldp_sync_state_update(struct ldp_igp_sync_if_state state);
 extern int ospf_ldp_sync_announce_update(struct ldp_igp_sync_announce announce);
-extern int ospf_ldp_sync_hello_update(struct ldp_igp_sync_hello hello);
+extern void
+ospf_ldp_sync_handle_client_close(struct zapi_client_close_info *info);
 extern void ospf_ldp_sync_state_req_msg(struct interface *ifp);
 extern void ospf_ldp_sync_init(void);
 extern void ospf_ldp_sync_gbl_exit(struct ospf *ospf, bool remove);
index 42fc3288cde21167a18495ab71c300ab723bd701..4c9db16c6b8ec46dea633ad8cf636d872a578002 100644 (file)
@@ -1480,17 +1480,17 @@ struct in_addr ospf_get_nssa_ip(struct ospf_area *area)
                        if (oi->area->external_routing == OSPF_AREA_NSSA)
                                if (oi->address
                                    && oi->address->family == AF_INET) {
-                                       if (best_default.s_addr == 0)
+                                       if (best_default.s_addr == INADDR_ANY)
                                                best_default =
                                                        oi->address->u.prefix4;
                                        if (oi->area == area)
                                                return oi->address->u.prefix4;
                                }
        }
-       if (best_default.s_addr != 0)
+       if (best_default.s_addr != INADDR_ANY)
                return best_default;
 
-       if (best_default.s_addr != 0)
+       if (best_default.s_addr != INADDR_ANY)
                return best_default;
 
        return fwd;
@@ -1708,11 +1708,11 @@ static void ospf_install_flood_nssa(struct ospf *ospf, struct ospf_lsa *lsa,
                        /* kevinm: not updating lsa anymore, just new */
                        extlsa = (struct as_external_lsa *)(new->data);
 
-                       if (extlsa->e[0].fwd_addr.s_addr == 0)
+                       if (extlsa->e[0].fwd_addr.s_addr == INADDR_ANY)
                                extlsa->e[0].fwd_addr = ospf_get_nssa_ip(
                                        area); /* this NSSA area in ifp */
 
-                       if (extlsa->e[0].fwd_addr.s_addr == 0) {
+                       if (extlsa->e[0].fwd_addr.s_addr == INADDR_ANY) {
                                if (IS_DEBUG_OSPF_NSSA)
                                        zlog_debug(
                                                "LSA[Type-7]: Could not build FWD-ADDR");
@@ -2300,9 +2300,9 @@ struct ospf_lsa *ospf_external_lsa_refresh(struct ospf *ospf,
                if (!ospf_redistribute_check(ospf, ei, &changed)) {
                        if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
                                zlog_debug(
-                                       "LSA[Type%d:%s] Could not be refreshed, redist check fail",
+                                       "LSA[Type%d:%pI4] Could not be refreshed, redist check fail",
                                        lsa->data->type,
-                                       inet_ntoa(lsa->data->id));
+                                       &lsa->data->id);
 
                        ospf_external_lsa_flush(ospf, ei->type, &ei->p,
                                                ei->ifindex /*, ei->nexthop */);
@@ -2789,7 +2789,7 @@ int ospf_check_nbr_status(struct ospf *ospf)
 static int ospf_maxage_lsa_remover(struct thread *thread)
 {
        struct ospf *ospf = THREAD_ARG(thread);
-       struct ospf_lsa *lsa;
+       struct ospf_lsa *lsa, *old;
        struct route_node *rn;
        int reschedule = 0;
 
@@ -2851,6 +2851,17 @@ static int ospf_maxage_lsa_remover(struct thread *thread)
 
                        /* Remove from lsdb. */
                        if (lsa->lsdb) {
+                               old = ospf_lsdb_lookup(lsa->lsdb, lsa);
+                               /* The max age LSA here must be the same
+                                * as the LSA in LSDB
+                                */
+                               if (old != lsa) {
+                                       flog_err(EC_OSPF_LSA_MISSING,
+                                       "%s: LSA[Type%d:%s]: LSA not in LSDB",
+                                       __func__, lsa->data->type,
+                                       inet_ntoa(lsa->data->id));
+                                       continue;
+                               }
                                ospf_discard_from_db(ospf, lsa->lsdb, lsa);
                                ospf_lsdb_delete(lsa->lsdb, lsa);
                        } else {
index bcf563a5ba3fff6ba7ddaf699f52b215aae1bf5f..590122e223a4634cd847c24ad0f974a9eee59ce9 100644 (file)
@@ -681,7 +681,7 @@ void ospf_route_table_print(struct vty *vty, struct route_table *rt)
                                        or->cost);
                                for (ALL_LIST_ELEMENTS_RO(or->paths, pnode,
                                                          path))
-                                       if (path->nexthop.s_addr != 0)
+                                       if (path->nexthop.s_addr != INADDR_ANY)
                                                vty_out(vty, "  -> %pI4\n",
                                                        &path->nexthop);
                                        else
index f9e11541fcbbde536c4cf834715978555181e793..bdc65d23bf64ccffdb930c28e8c39ddfd1c14761 100644 (file)
@@ -416,7 +416,7 @@ static void *route_set_metric_compile(const char *arg)
 {
        struct ospf_metric *metric;
 
-       metric = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
+       metric = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*metric));
        metric->used = false;
 
        if (all_digit(arg))
index 033046da0a3b6e7f28c0f3d39fde431e3ddca690..66dd9c7ca4ac9dbbf4d650a1aa7f7c0b70efa3ae 100644 (file)
@@ -1405,7 +1405,8 @@ static int ospf_snmp_if_update(struct interface *ifp)
                } else {
                        /* Unnumbered interfaces --> Sort them based on
                         * interface indexes */
-                       if (osif->addr.s_addr != 0 || osif->ifindex > ifindex)
+                       if (osif->addr.s_addr != INADDR_ANY
+                           || osif->ifindex > ifindex)
                                break;
                }
                pn = node;
@@ -2003,11 +2004,12 @@ static struct ospf_neighbor *ospf_snmp_nbr_lookup(struct ospf *ospf,
 
        for (ALL_LIST_ELEMENTS(ospf->oiflist, node, nnode, oi)) {
                for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
-                       if ((nbr = rn->info) != NULL && nbr != oi->nbr_self
+                       if ((nbr = rn->info) != NULL
+                           && nbr != oi->nbr_self
                            /* If EXACT match is needed, provide ALL entry found
                                        && nbr->state != NSM_Down
                             */
-                           && nbr->src.s_addr != 0) {
+                           && nbr->src.s_addr != INADDR_ANY) {
                                if (IPV4_ADDR_SAME(&nbr->src, nbr_addr)) {
                                        route_unlock_node(rn);
                                        return nbr;
@@ -2033,7 +2035,8 @@ static struct ospf_neighbor *ospf_snmp_nbr_lookup_next(struct in_addr *nbr_addr,
        for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, nn, oi)) {
                for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
                        if ((nbr = rn->info) != NULL && nbr != oi->nbr_self
-                           && nbr->state != NSM_Down && nbr->src.s_addr != 0) {
+                           && nbr->state != NSM_Down
+                           && nbr->src.s_addr != INADDR_ANY) {
                                if (first) {
                                        if (!min)
                                                min = nbr;
index b53719a402bf80a48e9bccd330b0080347ebd2a7..4665f53edbdaf648a062676fc5827109289c9038 100644 (file)
@@ -583,6 +583,21 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
                        struct router_lsa_link *l2 = NULL;
 
                        if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) {
+                               struct ospf_interface *oi = NULL;
+                               struct in_addr nexthop = {.s_addr = 0};
+
+                               oi = ospf_if_lookup_by_lsa_pos(area, lsa_pos);
+                               if (!oi) {
+                                       zlog_debug(
+                                               "%s: OI not found in LSA: lsa_pos: %d link_id:%s link_data:%s",
+                                               __func__, lsa_pos,
+                                               inet_ntop(AF_INET, &l->link_id,
+                                                         buf1, BUFSIZ),
+                                               inet_ntop(AF_INET,
+                                                         &l->link_data, buf2,
+                                                         BUFSIZ));
+                                       return 0;
+                               }
 
                                /*
                                 * If the destination is a router which connects
@@ -629,17 +644,12 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
                                 * as described above using a reverse lookup to
                                 * figure out the nexthop.
                                 */
+                               if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
+                                       struct ospf_neighbor *nbr_w = NULL;
 
-                               struct in_addr nexthop = {.s_addr = 0};
-                               struct ospf_interface *oi = NULL;
-                               struct ospf_neighbor *nbr_w = NULL;
-
-                               /* Calculating node is root node, link is P2P */
-                               if (area->spf_root_node) {
-                                       oi = ospf_if_lookup_by_lsa_pos(area,
-                                                                      lsa_pos);
-                                       if (oi->type
-                                           == OSPF_IFTYPE_POINTOPOINT) {
+                                       /* Calculating node is root node, link
+                                        * is P2P */
+                                       if (area->spf_root_node) {
                                                nbr_w = ospf_nbr_lookup_by_routerid(
                                                        oi->nbrs, &l->link_id);
                                                if (nbr_w) {
@@ -647,20 +657,45 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
                                                        nexthop = nbr_w->src;
                                                }
                                        }
-                               }
 
-                               /* Reverse lookup */
-                               if (!added) {
+                                       /* Reverse lookup */
+                                       if (!added) {
+                                               while ((l2 = ospf_get_next_link(
+                                                               w, v, l2))) {
+                                                       if (match_stub_prefix(
+                                                                   v->lsa,
+                                                                   l->link_data,
+                                                                   l2->link_data)) {
+                                                               added = 1;
+                                                               nexthop =
+                                                                       l2->link_data;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               } else if (oi->type
+                                          == OSPF_IFTYPE_POINTOMULTIPOINT) {
+                                       struct prefix_ipv4 la;
+
+                                       la.family = AF_INET;
+                                       la.prefixlen = oi->address->prefixlen;
+
+                                       /*
+                                        * V links to W on PtMP interface;
+                                        * find the interface address on W
+                                        */
                                        while ((l2 = ospf_get_next_link(w, v,
                                                                        l2))) {
-                                               if (match_stub_prefix(
-                                                           v->lsa,
-                                                           l->link_data,
-                                                           l2->link_data)) {
-                                                       added = 1;
-                                                       nexthop = l2->link_data;
-                                                       break;
-                                               }
+                                               la.prefix = l2->link_data;
+
+                                               if (prefix_cmp((struct prefix
+                                                                       *)&la,
+                                                              oi->address)
+                                                   != 0)
+                                                       continue;
+                                               added = 1;
+                                               nexthop = l2->link_data;
+                                               break;
                                        }
                                }
 
@@ -672,8 +707,8 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
                                        return 1;
                                } else
                                        zlog_info(
-                                               "%s: could not determine nexthop for link",
-                                               __func__);
+                                               "%s: could not determine nexthop for link %s",
+                                               __func__, oi->ifp->name);
                        } /* end point-to-point link from V to W */
                        else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) {
                                /*
@@ -1203,7 +1238,7 @@ ospf_rtrs_print (struct route_table *rtrs)
 
           for (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path))
             {
-              if (path->nexthop.s_addr == 0)
+              if (path->nexthop.s_addr == INADDR_ANY)
                 {
                   if (IS_DEBUG_OSPF_EVENT)
                     zlog_debug ("   directly attached to %s\r",
@@ -1432,8 +1467,11 @@ static int ospf_spf_calculate_schedule_worker(struct thread *thread)
 
        /* ABRs may require additional changes, see RFC 2328 16.7. */
        monotime(&start_time);
-       if (IS_OSPF_ABR(ospf))
+       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 */
index 71dea80538e18aaa61cd1fc089ec2fec692c339a..4c67d33cb9bbe54f682cf049e631a2c3ea3eedfc 100644 (file)
@@ -280,7 +280,7 @@ DEFPY (ospf_router_id,
        for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area))
                if (area->full_nbrs) {
                        vty_out(vty,
-                               "For this router-id change to take effect, save config and restart ospfd\n");
+                               "For this router-id change to take effect, use “clear ip ospf process” command\n");
                        return CMD_SUCCESS;
                }
 
@@ -313,7 +313,7 @@ DEFUN_HIDDEN (ospf_router_id_old,
        for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area))
                if (area->full_nbrs) {
                        vty_out(vty,
-                               "For this router-id change to take effect, save config and restart ospfd\n");
+                               "For this router-id change to take effect, use “clear ip ospf process” command\n");
                        return CMD_SUCCESS;
                }
 
@@ -346,7 +346,7 @@ DEFPY (no_ospf_router_id,
        for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area))
                if (area->full_nbrs) {
                        vty_out(vty,
-                               "For this router-id change to take effect, save config and restart ospfd\n");
+                               "For this router-id change to take effect, use “clear ip ospf process” command\n");
                        return CMD_SUCCESS;
                }
 
@@ -583,7 +583,7 @@ DEFUN (ospf_network_area,
                        "Please remove all ip ospf area x.x.x.x commands first.\n");
                if (IS_DEBUG_OSPF_EVENT)
                        zlog_debug(
-                               "%s ospf vrf %s num of %u ip osp area x config",
+                               "%s ospf vrf %s num of %u ip ospf area x config",
                                __func__, ospf->name ? ospf->name : "NIL",
                                ospf->if_ospf_cli_count);
                return CMD_WARNING_CONFIG_FAILED;
@@ -2702,6 +2702,10 @@ static void show_ip_ospf_area(struct vty *vty, struct ospf_area *area,
                                        json_object_boolean_true_add(
                                                json_area,
                                                "nssaTranslatorAlways");
+                               else
+                                       json_object_boolean_true_add(
+                                               json_area,
+                                               "nssaTranslatorNever");
                        } else {
                                json_object_boolean_true_add(json_area, "abr");
                                if (area->NSSATranslatorRole
@@ -2716,29 +2720,32 @@ static void show_ip_ospf_area(struct vty *vty, struct ospf_area *area,
                        }
                } else {
                        vty_out(vty,
-                               "   It is an NSSA configuration. \n   Elected NSSA/ABR performs type-7/type-5 LSA translation. \n");
+                               "   It is an NSSA configuration.\n   Elected NSSA/ABR performs type-7/type-5 LSA translation.\n");
                        if (!IS_OSPF_ABR(area->ospf))
                                vty_out(vty,
-                                       "   It is not ABR, therefore not Translator. \n");
+                                       "   It is not ABR, therefore not Translator.\n");
                        else if (area->NSSATranslatorState) {
                                vty_out(vty, "   We are an ABR and ");
                                if (area->NSSATranslatorRole
                                    == OSPF_NSSA_ROLE_CANDIDATE)
                                        vty_out(vty,
-                                               "the NSSA Elected Translator. \n");
+                                               "the NSSA Elected Translator.\n");
                                else if (area->NSSATranslatorRole
                                         == OSPF_NSSA_ROLE_ALWAYS)
                                        vty_out(vty,
-                                               "always an NSSA Translator. \n");
+                                               "always an NSSA Translator.\n");
+                               else
+                                       vty_out(vty,
+                                               "never an NSSA Translator.\n");
                        } else {
                                vty_out(vty, "   We are an ABR, but ");
                                if (area->NSSATranslatorRole
                                    == OSPF_NSSA_ROLE_CANDIDATE)
                                        vty_out(vty,
-                                               "not the NSSA Elected Translator. \n");
+                                               "not the NSSA Elected Translator.\n");
                                else
                                        vty_out(vty,
-                                               "never an NSSA Translator. \n");
+                                               "never an NSSA Translator.\n");
                        }
                }
        }
@@ -3358,6 +3365,54 @@ DEFUN (show_ip_ospf_instance,
        return ret;
 }
 
+static void ospf_interface_auth_show(struct vty *vty, struct ospf_interface *oi,
+                                    json_object *json, bool use_json)
+{
+       int auth_type;
+
+       auth_type = OSPF_IF_PARAM(oi, auth_type);
+
+       switch (auth_type) {
+       case OSPF_AUTH_NULL:
+               if (use_json)
+                       json_object_string_add(json, "authentication",
+                                              "authenticationNone");
+               else
+                       vty_out(vty, "  Authentication NULL is enabled\n");
+               break;
+       case OSPF_AUTH_SIMPLE: {
+               if (use_json)
+                       json_object_string_add(json, "authentication",
+                                              "authenticationSimplePassword");
+               else
+                       vty_out(vty,
+                               "  Simple password authentication enabled\n");
+               break;
+       }
+       case OSPF_AUTH_CRYPTOGRAPHIC: {
+               struct crypt_key *ckey;
+
+               if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt)))
+                       return;
+
+               ckey = listgetdata(listtail(OSPF_IF_PARAM(oi, auth_crypt)));
+               if (ckey) {
+                       if (use_json) {
+                               json_object_string_add(json, "authentication",
+                                                      "authenticationMessageDigest");
+                       } else {
+                               vty_out(vty,
+                                       "  Cryptographic authentication enabled\n");
+                               vty_out(vty, "  Algorithm:MD5\n");
+                       }
+               }
+               break;
+       }
+       default:
+               break;
+       }
+}
+
 static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
                                       struct interface *ifp,
                                       json_object *json_interface_sub,
@@ -3679,6 +3734,9 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
                                ospf_nbr_count(oi, 0),
                                ospf_nbr_count(oi, NSM_Full));
                ospf_bfd_interface_show(vty, ifp, json_interface_sub, use_json);
+
+               /* OSPF Authentication information */
+               ospf_interface_auth_show(vty, oi, json_interface_sub, use_json);
        }
 }
 
@@ -5793,9 +5851,8 @@ static int show_lsa_summary(struct vty *vty, struct ospf_lsa *lsa, int self,
                                /* LSA common part show. */
                                vty_out(vty, "%-15pI4",
                                        &lsa->data->id);
-                               vty_out(vty, "%-15s %4d 0x%08lx 0x%04x",
-                                       inet_ntoa(lsa->data->adv_router),
-                                       LS_AGE(lsa),
+                               vty_out(vty, "%-15pI4 %4d 0x%08lx 0x%04x",
+                                       &lsa->data->adv_router, LS_AGE(lsa),
                                        (unsigned long)ntohl(
                                                lsa->data->ls_seqnum),
                                        ntohs(lsa->data->checksum));
@@ -5809,10 +5866,13 @@ static int show_lsa_summary(struct vty *vty, struct ospf_lsa *lsa, int self,
                                         ntohs(lsa->data->checksum));
                                json_object_string_add(
                                        json_lsa, "lsId",
-                                       inet_ntoa(lsa->data->id));
+                                       inet_ntop(AF_INET, &lsa->data->id,
+                                                 buf, sizeof(buf)));
                                json_object_string_add(
                                        json_lsa, "advertisedRouter",
-                                       inet_ntoa(lsa->data->adv_router));
+                                       inet_ntop(AF_INET,
+                                                 &lsa->data->adv_router,
+                                                 buf, sizeof(buf)));
                                json_object_int_add(json_lsa, "lsaAge",
                                                    LS_AGE(lsa));
                                json_object_string_add(
@@ -5948,6 +6008,7 @@ static const char *const show_database_header[] = {
 static void show_ip_ospf_database_header(struct vty *vty, struct ospf_lsa *lsa,
                                         json_object *json)
 {
+       char buf[PREFIX_STRLEN];
        struct router_lsa *rlsa = (struct router_lsa *)lsa->data;
 
        if (!json) {
@@ -6029,9 +6090,12 @@ static void show_ip_ospf_database_header(struct vty *vty, struct ospf_lsa *lsa,
                        json, "lsaType",
                        lookup_msg(ospf_lsa_type_msg, lsa->data->type, NULL));
                json_object_string_add(json, "linkStateId",
-                                      inet_ntoa(lsa->data->id));
+                                      inet_ntop(AF_INET, &lsa->data->id,
+                                                buf, sizeof(buf)));
                json_object_string_add(json, "advertisingRouter",
-                                      inet_ntoa(lsa->data->adv_router));
+                                      inet_ntop(AF_INET,
+                                                &lsa->data->adv_router,
+                                                buf, sizeof(buf)));
                json_object_string_add(json, "lsaSeqNumber", seqnum);
                json_object_string_add(json, "checksum", checksum);
                json_object_int_add(json, "length", ntohs(lsa->data->length));
@@ -6076,6 +6140,7 @@ static void show_ip_ospf_database_router_links(struct vty *vty,
        json_object *json_links = NULL;
        json_object *json_link = NULL;
        int metric = 0;
+       char buf[PREFIX_STRLEN];
 
        if (json)
                json_links = json_object_new_object();
@@ -6093,10 +6158,13 @@ static void show_ip_ospf_database_router_links(struct vty *vty,
                                               link_type_desc[type]);
                        json_object_string_add(json_link,
                                               link_id_desc_json[type],
-                                              inet_ntoa(rl->link[i].link_id));
+                                              inet_ntop(AF_INET,
+                                                        &rl->link[i].link_id,
+                                                        buf, sizeof(buf)));
                        json_object_string_add(
                                json_link, link_data_desc_json[type],
-                               inet_ntoa(rl->link[i].link_data));
+                               inet_ntop(AF_INET, &rl->link[i].link_data,
+                                         buf, sizeof(buf)));
                        json_object_int_add(json_link, "numOfTosMetrics",
                                            metric);
                        json_object_int_add(json_link, "tos0Metric",
@@ -6151,6 +6219,7 @@ static int show_network_lsa_detail(struct vty *vty, struct ospf_lsa *lsa,
                                   json_object *json)
 {
        int length, i;
+       char buf[PREFIX_STRLEN];
        json_object *json_attached_rt = NULL;
        json_object *json_router = NULL;
 
@@ -6180,10 +6249,13 @@ static int show_network_lsa_detail(struct vty *vty, struct ospf_lsa *lsa,
                                json_router = json_object_new_object();
                                json_object_string_add(
                                        json_router, "attachedRouterId",
-                                       inet_ntoa(nl->routers[i]));
+                                       inet_ntop(AF_INET, &nl->routers[i],
+                                                 buf, sizeof(buf)));
                                json_object_object_add(
                                        json_attached_rt,
-                                       inet_ntoa(nl->routers[i]), json_router);
+                                       inet_ntop(AF_INET, &(nl->routers[i]),
+                                                 buf, sizeof(buf)),
+                                       json_router);
                        }
        }
 
@@ -6250,6 +6322,7 @@ static int show_summary_asbr_lsa_detail(struct vty *vty, struct ospf_lsa *lsa,
 static int show_as_external_lsa_detail(struct vty *vty, struct ospf_lsa *lsa,
                                       json_object *json)
 {
+       char buf[PREFIX_STRLEN];
        int tos = 0;
 
        if (lsa != NULL) {
@@ -6285,7 +6358,9 @@ static int show_as_external_lsa_detail(struct vty *vty, struct ospf_lsa *lsa,
                        json_object_int_add(json, "metric",
                                            GET_METRIC(al->e[0].metric));
                        json_object_string_add(json, "forwardAddress",
-                                              inet_ntoa(al->e[0].fwd_addr));
+                                              inet_ntop(AF_INET,
+                                                        &(al->e[0].fwd_addr),
+                                                        buf, sizeof(buf)));
                        json_object_int_add(
                                json, "externalRouteTag",
                                (route_tag_t)ntohl(al->e[0].route_tag));
@@ -6323,6 +6398,7 @@ show_as_external_lsa_stdvty (struct ospf_lsa *lsa)
 static int show_as_nssa_lsa_detail(struct vty *vty, struct ospf_lsa *lsa,
                                   json_object *json)
 {
+       char buf[PREFIX_STRLEN];
        int tos = 0;
 
        if (lsa != NULL) {
@@ -6359,7 +6435,9 @@ static int show_as_nssa_lsa_detail(struct vty *vty, struct ospf_lsa *lsa,
                        json_object_int_add(json, "metric",
                                            GET_METRIC(al->e[0].metric));
                        json_object_string_add(json, "nssaForwardAddress",
-                                              inet_ntoa(al->e[0].fwd_addr));
+                                              inet_ntop(AF_INET,
+                                                        &al->e[0].fwd_addr,
+                                                        buf, sizeof(buf)));
                        json_object_int_add(
                                json, "externalRouteTag",
                                (route_tag_t)ntohl(al->e[0].route_tag));
@@ -6455,6 +6533,7 @@ static void show_lsa_detail(struct vty *vty, struct ospf *ospf, int type,
 {
        struct listnode *node;
        struct ospf_area *area;
+       char buf[PREFIX_STRLEN];
        json_object *json_lsa_type = NULL;
        json_object *json_areas = NULL;
        json_object *json_lsa_array = NULL;
@@ -6492,7 +6571,10 @@ static void show_lsa_detail(struct vty *vty, struct ospf *ospf, int type,
                        } else {
                                json_lsa_array = json_object_new_array();
                                json_object_object_add(json_areas,
-                                                      inet_ntoa(area->area_id),
+                                                      inet_ntop(AF_INET,
+                                                                &area->area_id,
+                                                                buf,
+                                                                sizeof(buf)),
                                                       json_lsa_array);
                        }
 
@@ -6516,6 +6598,7 @@ static void show_lsa_detail_adv_router_proc(struct vty *vty,
                                            struct in_addr *adv_router,
                                            json_object *json)
 {
+       char buf[PREFIX_STRLEN];
        struct route_node *rn;
        struct ospf_lsa *lsa;
 
@@ -6535,7 +6618,10 @@ static void show_lsa_detail_adv_router_proc(struct vty *vty,
                                                vty, lsa, json_lsa);
                                if (json)
                                        json_object_object_add(
-                                               json, inet_ntoa(lsa->data->id),
+                                               json,
+                                               inet_ntop(AF_INET,
+                                                         &lsa->data->id,
+                                                         buf, sizeof(buf)),
                                                json_lsa);
                        }
                }
@@ -6548,6 +6634,7 @@ static void show_lsa_detail_adv_router(struct vty *vty, struct ospf *ospf,
 {
        struct listnode *node;
        struct ospf_area *area;
+       char buf[PREFIX_STRLEN];
        json_object *json_lstype = NULL;
        json_object *json_area = NULL;
 
@@ -6580,7 +6667,10 @@ static void show_lsa_detail_adv_router(struct vty *vty, struct ospf *ospf,
 
                        if (json)
                                json_object_object_add(json_lstype,
-                                                      inet_ntoa(area->area_id),
+                                                      inet_ntop(AF_INET,
+                                                                &area->area_id,
+                                                                buf,
+                                                                sizeof(buf)),
                                                       json_area);
                }
                break;
@@ -6598,6 +6688,7 @@ static void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf,
        struct route_node *rn;
        struct ospf_area *area;
        struct listnode *node;
+       char buf[PREFIX_STRLEN];
        json_object *json_areas = NULL;
        json_object *json_area = NULL;
        json_object *json_lsa = NULL;
@@ -6658,7 +6749,9 @@ static void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf,
                }
                if (json)
                        json_object_object_add(json_areas,
-                                              inet_ntoa(area->area_id),
+                                              inet_ntop(AF_INET,
+                                                        &area->area_id,
+                                                        buf, sizeof(buf)),
                                               json_area);
        }
 
@@ -6710,6 +6803,7 @@ static void show_ip_ospf_database_maxage(struct vty *vty, struct ospf *ospf,
                                         json_object *json)
 {
        struct route_node *rn;
+       char buf[PREFIX_STRLEN];
        json_object *json_maxage = NULL;
 
        if (!json)
@@ -6725,8 +6819,8 @@ static void show_ip_ospf_database_maxage(struct vty *vty, struct ospf *ospf,
                        if (!json) {
                                vty_out(vty, "Link type: %d\n",
                                        lsa->data->type);
-                               vty_out(vty, "Link State ID: %s\n",
-                                       inet_ntoa(lsa->data->id));
+                               vty_out(vty, "Link State ID: %pI4\n",
+                                       &lsa->data->id);
                                vty_out(vty, "Advertising Router: %pI4\n",
                                        &lsa->data->adv_router);
                                vty_out(vty, "LSA lock count: %d\n", lsa->lock);
@@ -6737,15 +6831,21 @@ static void show_ip_ospf_database_maxage(struct vty *vty, struct ospf *ospf,
                                                    lsa->data->type);
                                json_object_string_add(
                                        json_lsa, "linkStateId",
-                                       inet_ntoa(lsa->data->id));
+                                       inet_ntop(AF_INET, &lsa->data->id,
+                                                 buf, sizeof(buf)));
                                json_object_string_add(
                                        json_lsa, "advertisingRouter",
-                                       inet_ntoa(lsa->data->adv_router));
+                                       inet_ntop(AF_INET,
+                                                 &lsa->data->adv_router,
+                                                 buf, sizeof(buf)));
                                json_object_int_add(json_lsa, "lsaLockCount",
                                                    lsa->lock);
-                               json_object_object_add(json_maxage,
-                                                      inet_ntoa(lsa->data->id),
-                                                      json_lsa);
+                               json_object_object_add(
+                                       json_maxage,
+                                       inet_ntop(AF_INET,
+                                                 &lsa->data->id,
+                                                 buf, sizeof(buf)),
+                                       json_lsa);
                        }
                }
        }
@@ -6779,6 +6879,7 @@ static int show_ip_ospf_database_common(struct vty *vty, struct ospf *ospf,
        int idx_type = 4;
        int type, ret;
        struct in_addr id, adv_router;
+       char buf[PREFIX_STRLEN];
        json_object *json_vrf = NULL;
 
        if (uj) {
@@ -6801,7 +6902,8 @@ static int show_ip_ospf_database_common(struct vty *vty, struct ospf *ospf,
        /* Show Router ID. */
        if (uj) {
                json_object_string_add(json_vrf, "routerId",
-                                      inet_ntoa(ospf->router_id));
+                                      inet_ntop(AF_INET, &ospf->router_id,
+                                                buf, sizeof(buf)));
        } else {
                vty_out(vty, "\n       OSPF Router with ID (%pI4)\n\n",
                        &ospf->router_id);
@@ -7131,6 +7233,7 @@ static int show_ip_ospf_database_type_adv_router_common(struct vty *vty,
        int idx_type = 4;
        int type, ret;
        struct in_addr adv_router;
+       char buf[PREFIX_STRLEN];
        json_object *json_vrf = NULL;
 
        if (uj) {
@@ -7153,7 +7256,8 @@ static int show_ip_ospf_database_type_adv_router_common(struct vty *vty,
        /* Show Router ID. */
        if (uj) {
                json_object_string_add(json_vrf, "routerId",
-                                      inet_ntoa(ospf->router_id));
+                                      inet_ntop(AF_INET, &ospf->router_id,
+                                                buf, sizeof(buf)));
        } else {
                vty_out(vty, "\n       OSPF Router with ID (%pI4)\n\n",
                        &ospf->router_id);
@@ -7263,8 +7367,8 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router,
                                        continue;
                                ospf_output = true;
                                ret = show_ip_ospf_database_type_adv_router_common(
-                                       vty, ospf, idx ? 1 : 0, argc, argv,
-                                       use_vrf, json, uj);
+                                       vty, ospf, 2, argc, argv, use_vrf, json,
+                                       uj);
                        }
                        if (!ospf_output)
                                vty_out(vty, "%% OSPF instance not found\n");
@@ -7276,8 +7380,7 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router,
                        }
 
                        ret = show_ip_ospf_database_type_adv_router_common(
-                               vty, ospf, idx ? 1 : 0, argc, argv, use_vrf,
-                               json, uj);
+                               vty, ospf, 2, argc, argv, use_vrf, json, uj);
                }
        } else {
                /* Display default ospf (instance 0) info */
@@ -8818,6 +8921,7 @@ DEFUN (no_ip_ospf_area,
        struct ospf_if_params *params;
        unsigned short instance = 0;
        struct in_addr addr;
+       struct in_addr area_id;
 
        if (argv_find(argv, argc, "(1-65535)", &idx))
                instance = strtol(argv[idx]->arg, NULL, 10);
@@ -8845,6 +8949,7 @@ DEFUN (no_ip_ospf_area,
        } else
                params = IF_DEF_PARAMS(ifp);
 
+       area_id = params->if_area;
        if (!OSPF_IF_PARAM_CONFIGURED(params, if_area)) {
                vty_out(vty,
                        "Can't find specified interface area configuration.\n");
@@ -8860,6 +8965,7 @@ DEFUN (no_ip_ospf_area,
        if (ospf) {
                ospf_interface_area_unset(ospf, ifp);
                ospf->if_ospf_cli_count--;
+               ospf_area_check_free(ospf, area_id);
        }
 
        return CMD_SUCCESS;
@@ -10443,7 +10549,8 @@ static void show_ip_ospf_route_network(struct vty *vty, struct ospf *ospf,
                                if (if_lookup_by_index(path->ifindex,
                                                       ospf->vrf_id)) {
 
-                                       if (path->nexthop.s_addr == 0) {
+                                       if (path->nexthop.s_addr
+                                           == INADDR_ANY) {
                                                if (json) {
                                                        json_object_string_add(
                                                                json_nexthop,
@@ -10588,7 +10695,8 @@ static void show_ip_ospf_route_router(struct vty *vty, struct ospf *ospf,
                                }
                                if (if_lookup_by_index(path->ifindex,
                                                       ospf->vrf_id)) {
-                                       if (path->nexthop.s_addr == 0) {
+                                       if (path->nexthop.s_addr
+                                           == INADDR_ANY) {
                                                if (json) {
                                                        json_object_string_add(
                                                                json_nexthop,
@@ -10716,7 +10824,7 @@ static void show_ip_ospf_route_external(struct vty *vty, struct ospf *ospf,
                        }
 
                        if (if_lookup_by_index(path->ifindex, ospf->vrf_id)) {
-                               if (path->nexthop.s_addr == 0) {
+                               if (path->nexthop.s_addr == INADDR_ANY) {
                                        if (json) {
                                                json_object_string_add(
                                                        json_nexthop, "ip",
@@ -11122,6 +11230,70 @@ DEFUN (show_ip_ospf_vrfs,
 
        return CMD_SUCCESS;
 }
+DEFPY (clear_ip_ospf_neighbor,
+       clear_ip_ospf_neighbor_cmd,
+       "clear ip ospf [(1-65535)]$instance neighbor [A.B.C.D$nbr_id]",
+       CLEAR_STR
+       IP_STR
+       "OSPF information\n"
+       "Instance ID\n"
+       "Reset OSPF Neighbor\n"
+       "Neighbor ID\n")
+{
+       struct listnode *node;
+       struct ospf *ospf = NULL;
+
+       /* If user does not specify the arguments,
+        * instance = 0 and nbr_id = 0.0.0.0
+        */
+       if (instance != 0) {
+               /* This means clear only the particular ospf process */
+               ospf = ospf_lookup_instance(instance);
+               if (ospf == NULL)
+                       return CMD_NOT_MY_INSTANCE;
+       }
+
+       /* Clear all the ospf processes */
+       for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
+               if (!ospf->oi_running)
+                       continue;
+
+               ospf_neighbor_reset(ospf, nbr_id, nbr_id_str);
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFPY (clear_ip_ospf_process,
+       clear_ip_ospf_process_cmd,
+       "clear ip ospf [(1-65535)]$instance process",
+       CLEAR_STR
+       IP_STR
+       "OSPF information\n"
+       "Instance ID\n"
+       "Reset OSPF Process\n")
+{
+       struct listnode *node;
+       struct ospf *ospf = NULL;
+
+       /* Check if instance is not passed as an argument */
+       if (instance != 0) {
+               /* This means clear only the particular ospf process */
+               ospf = ospf_lookup_instance(instance);
+               if (ospf == NULL)
+                       return CMD_NOT_MY_INSTANCE;
+       }
+
+       /* Clear all the ospf processes */
+       for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
+               if (!ospf->oi_running)
+                       continue;
+
+               ospf_process_reset(ospf);
+       }
+
+       return CMD_SUCCESS;
+}
 
 static const char *const ospf_abr_type_str[] = {
        "unknown", "standard", "ibm", "cisco", "shortcut"
@@ -11399,6 +11571,30 @@ static const char *const ospf_int_type_str[] = {
        "loopback"
 };
 
+static const char *interface_config_auth_str(struct ospf_if_params *params)
+{
+       if (!OSPF_IF_PARAM_CONFIGURED(params, auth_type)
+           || params->auth_type == OSPF_AUTH_NOTSET)
+               return NULL;
+
+       /* Translation tables are not that much help
+        * here due to syntax
+        * of the simple option */
+       switch (params->auth_type) {
+
+       case OSPF_AUTH_NULL:
+               return " null";
+
+       case OSPF_AUTH_SIMPLE:
+               return "";
+
+       case OSPF_AUTH_CRYPTOGRAPHIC:
+               return " message-digest";
+       }
+
+       return "";
+}
+
 static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
 {
        struct listnode *node;
@@ -11406,6 +11602,7 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
        struct crypt_key *ck;
        struct route_node *rn = NULL;
        struct ospf_if_params *params;
+       const char *auth_str;
        int write = 0;
        struct ospf *ospf = vrf->info;
 
@@ -11443,32 +11640,8 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
                        }
 
                        /* OSPF interface authentication print */
-                       if (OSPF_IF_PARAM_CONFIGURED(params, auth_type)
-                           && params->auth_type != OSPF_AUTH_NOTSET) {
-                               const char *auth_str;
-
-                               /* Translation tables are not that much help
-                               * here due to syntax
-                               * of the simple option */
-                               switch (params->auth_type) {
-
-                               case OSPF_AUTH_NULL:
-                                       auth_str = " null";
-                                       break;
-
-                               case OSPF_AUTH_SIMPLE:
-                                       auth_str = "";
-                                       break;
-
-                               case OSPF_AUTH_CRYPTOGRAPHIC:
-                                       auth_str = " message-digest";
-                                       break;
-
-                               default:
-                                       auth_str = "";
-                                       break;
-                               }
-
+                       auth_str = interface_config_auth_str(params);
+                       if (auth_str) {
                                vty_out(vty, " ip ospf authentication%s",
                                        auth_str);
                                if (params != IF_DEF_PARAMS(ifp) && rn)
@@ -11819,6 +11992,7 @@ static int config_write_virtual_link(struct vty *vty, struct ospf *ospf)
 {
        struct listnode *node;
        struct ospf_vl_data *vl_data;
+       const char *auth_str;
        char buf[INET_ADDRSTRLEN];
 
        /* Virtual-Link print */
@@ -11851,6 +12025,13 @@ static int config_write_virtual_link(struct vty *vty, struct ospf *ospf)
                        else
                                vty_out(vty, " area %s virtual-link %pI4\n", buf,
                                        &vl_data->vl_peer);
+                       /* Auth type */
+                       auth_str = interface_config_auth_str(
+                               IF_DEF_PARAMS(oi->ifp));
+                       if (auth_str)
+                               vty_out(vty,
+                                       " area %s virtual-link %pI4 authentication%s\n",
+                                       buf, &vl_data->vl_peer, auth_str);
                        /* Auth key */
                        if (IF_DEF_PARAMS(vl_data->vl_oi->ifp)->auth_simple[0]
                            != '\0')
@@ -12076,7 +12257,7 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf)
        }
 
        /* Router ID print. */
-       if (ospf->router_id_static.s_addr != 0)
+       if (ospf->router_id_static.s_addr != INADDR_ANY)
                vty_out(vty, " ospf router-id %pI4\n",
                        &ospf->router_id_static);
 
@@ -12509,6 +12690,8 @@ DEFUN (clear_ip_ospf_interface,
 void ospf_vty_clear_init(void)
 {
        install_element(ENABLE_NODE, &clear_ip_ospf_interface_cmd);
+       install_element(ENABLE_NODE, &clear_ip_ospf_process_cmd);
+       install_element(ENABLE_NODE, &clear_ip_ospf_neighbor_cmd);
 }
 
 
index d449f9d2fa79bb7836bc54b67c432e068bbd8481..2d02619ae395263a911a36e80a2dbae61e851ca6 100644 (file)
@@ -1915,7 +1915,7 @@ int ospf_zebra_label_manager_connect(void)
        set_nonblocking(zclient_sync->sock);
 
        /* Send hello to notify zebra this is a synchronous client */
-       if (zclient_send_hello(zclient_sync) < 0) {
+       if (zclient_send_hello(zclient_sync) == ZCLIENT_SEND_FAILURE) {
                zlog_warn("%s: failed sending hello for synchronous zclient!",
                          __func__);
                close(zclient_sync->sock);
@@ -1956,7 +1956,6 @@ static int ospf_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
        struct zapi_opaque_msg info;
        struct ldp_igp_sync_if_state state;
        struct ldp_igp_sync_announce announce;
-       struct ldp_igp_sync_hello hello;
        int ret = 0;
 
        s = zclient->ibuf;
@@ -1973,10 +1972,6 @@ static int ospf_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
                STREAM_GET(&announce, s, sizeof(announce));
                ret = ospf_ldp_sync_announce_update(announce);
                break;
-       case LDP_IGP_SYNC_HELLO_UPDATE:
-               STREAM_GET(&hello, s, sizeof(hello));
-               ret = ospf_ldp_sync_hello_update(hello);
-               break;
        default:
                break;
        }
@@ -1986,6 +1981,20 @@ stream_failure:
        return ret;
 }
 
+static int ospf_zebra_client_close_notify(ZAPI_CALLBACK_ARGS)
+{
+       int ret = 0;
+
+       struct zapi_client_close_info info;
+
+       if (zapi_client_close_notify_decode(zclient->ibuf, &info) < 0)
+               return -1;
+
+       ospf_ldp_sync_handle_client_close(&info);
+
+       return ret;
+}
+
 void ospf_zebra_init(struct thread_master *master, unsigned short instance)
 {
        /* Allocate zebra structure. */
@@ -2021,6 +2030,8 @@ void ospf_zebra_init(struct thread_master *master, unsigned short instance)
        prefix_list_delete_hook(ospf_prefix_list_update);
 
        zclient->opaque_msg_handler = ospf_opaque_msg_handler;
+
+       zclient->zebra_client_close_notify = ospf_zebra_client_close_notify;
 }
 
 void ospf_zebra_send_arp(const struct interface *ifp, const struct prefix *p)
index a839806720ea22d39baef04b88216f31006aded1..bab75995b7d0dca36e2f864074f7c73d6c6647a7 100644 (file)
@@ -87,13 +87,15 @@ static void ospf_finish_final(struct ospf *);
 
 #define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1
 
-void ospf_router_id_update(struct ospf *ospf)
+void ospf_process_refresh_data(struct ospf *ospf, bool reset)
 {
        struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id);
        struct in_addr router_id, router_id_old;
        struct ospf_interface *oi;
        struct interface *ifp;
-       struct listnode *node;
+       struct listnode *node, *nnode;
+       struct ospf_area *area;
+       bool rid_change = false;
 
        if (!ospf->oi_running) {
                if (IS_DEBUG_OSPF_EVENT)
@@ -115,9 +117,9 @@ void ospf_router_id_update(struct ospf *ospf)
                disruptive.
             3. Last choice: just go with whatever the zebra daemon recommends.
        */
-       if (ospf->router_id_static.s_addr != 0)
+       if (ospf->router_id_static.s_addr != INADDR_ANY)
                router_id = ospf->router_id_static;
-       else if (ospf->router_id.s_addr != 0)
+       else if (ospf->router_id.s_addr != INADDR_ANY)
                router_id = ospf->router_id;
        else
                router_id = ospf->router_id_zebra;
@@ -126,8 +128,8 @@ void ospf_router_id_update(struct ospf *ospf)
                zlog_debug("Router-ID[OLD:%pI4]: Update to %pI4",
                           &ospf->router_id, &router_id);
 
-       if (!IPV4_ADDR_SAME(&router_id_old, &router_id)) {
-
+       rid_change = !(IPV4_ADDR_SAME(&router_id_old, &router_id));
+       if (rid_change || (reset)) {
                for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
                        /* Some nbrs are identified by router_id, these needs
                         * to be rebuilt. Possible optimization would be to do
@@ -149,16 +151,8 @@ void ospf_router_id_update(struct ospf *ospf)
                                ospf_if_up(oi);
                }
 
-               /* Flush (inline) all external LSAs based on the OSPF_LSA_SELF
-                * flag */
-               if (ospf->lsdb) {
-                       struct route_node *rn;
-                       struct ospf_lsa *lsa;
-
-                       LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa)
-                               if (IS_LSA_SELF(lsa))
-                                       ospf_lsa_flush_schedule(ospf, lsa);
-               }
+               /* Flush (inline) all the self originated LSAs */
+               ospf_flush_self_originated_lsas_now(ospf);
 
                ospf->router_id = router_id;
                if (IS_DEBUG_OSPF_EVENT)
@@ -183,24 +177,81 @@ void ospf_router_id_update(struct ospf *ospf)
                        LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa) {
                                /* AdvRouter and Router ID is the same. */
                                if (IPV4_ADDR_SAME(&lsa->data->adv_router,
-                                                  &ospf->router_id)) {
+                                       &ospf->router_id) && rid_change) {
                                        SET_FLAG(lsa->flags,
                                                 OSPF_LSA_SELF_CHECKED);
                                        SET_FLAG(lsa->flags, OSPF_LSA_SELF);
                                        ospf_lsa_flush_schedule(ospf, lsa);
                                }
+                               /* The above flush will send immediately
+                                * So discard the LSA to originate new
+                                */
+                               ospf_discard_from_db(ospf, ospf->lsdb, lsa);
                        }
+
+                       LSDB_LOOP (OPAQUE_AS_LSDB(ospf), rn, lsa)
+                               ospf_discard_from_db(ospf, ospf->lsdb, lsa);
+
+                       ospf_lsdb_delete_all(ospf->lsdb);
                }
 
+               /* Delete the LSDB */
+               for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area))
+                       ospf_area_lsdb_discard_delete(area);
+
                /* update router-lsa's for each area */
                ospf_router_lsa_update(ospf);
 
                /* update ospf_interface's */
-               FOR_ALL_INTERFACES (vrf, ifp)
-                       ospf_if_update(ospf, ifp);
+               FOR_ALL_INTERFACES (vrf, ifp) {
+                       if (reset)
+                               ospf_if_reset(ifp);
+                       else
+                               ospf_if_update(ospf, ifp);
+               }
 
                ospf_external_lsa_rid_change(ospf);
        }
+
+       ospf->inst_shutdown = 0;
+}
+
+void ospf_router_id_update(struct ospf *ospf)
+{
+       ospf_process_refresh_data(ospf, false);
+}
+
+void ospf_process_reset(struct ospf *ospf)
+{
+       ospf_process_refresh_data(ospf, true);
+}
+
+void ospf_neighbor_reset(struct ospf *ospf, struct in_addr nbr_id,
+                       const char *nbr_str)
+{
+       struct route_node *rn;
+       struct ospf_neighbor *nbr;
+       struct ospf_interface *oi;
+       struct listnode *node;
+
+       /* Clear only a particular nbr with nbr router id as nbr_id */
+       if (nbr_str != NULL) {
+               for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
+                       nbr = ospf_nbr_lookup_by_routerid(oi->nbrs, &nbr_id);
+                       if (nbr)
+                               OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr);
+               }
+               return;
+       }
+
+       /* send Neighbor event KillNbr to all associated neighbors. */
+       for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
+               for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
+                       nbr = rn->info;
+                       if (nbr && (nbr != oi->nbr_self))
+                               OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr);
+               }
+       }
 }
 
 /* For OSPF area sort by area id. */
@@ -384,12 +435,50 @@ struct ospf *ospf_lookup_by_inst_name(unsigned short instance, const char *name)
        return NULL;
 }
 
-struct ospf *ospf_get(unsigned short instance, const char *name, bool *created)
+static void ospf_init(struct ospf *ospf)
 {
-       struct ospf *ospf;
        struct vrf *vrf;
        struct interface *ifp;
 
+       ospf_opaque_type11_lsa_init(ospf);
+
+       if (ospf->vrf_id != VRF_UNKNOWN)
+               ospf->oi_running = 1;
+
+       /* Activate 'ip ospf area x' configured interfaces for given
+        * vrf. Activate area on vrf x aware interfaces.
+        * vrf_enable callback calls router_id_update which
+        * internally will call ospf_if_update to trigger
+        * network_run_state
+        */
+       vrf = vrf_lookup_by_id(ospf->vrf_id);
+
+       FOR_ALL_INTERFACES (vrf, ifp) {
+               struct ospf_if_params *params;
+               struct route_node *rn;
+               uint32_t count = 0;
+
+               params = IF_DEF_PARAMS(ifp);
+               if (OSPF_IF_PARAM_CONFIGURED(params, if_area))
+                       count++;
+
+               for (rn = route_top(IF_OIFS_PARAMS(ifp)); rn; rn = route_next(rn))
+                       if ((params = rn->info) && OSPF_IF_PARAM_CONFIGURED(params, if_area))
+                               count++;
+
+               if (count > 0) {
+                       ospf_interface_area_set(ospf, ifp);
+                       ospf->if_ospf_cli_count += count;
+               }
+       }
+
+       ospf_router_id_update(ospf);
+}
+
+struct ospf *ospf_get(unsigned short instance, const char *name, bool *created)
+{
+       struct ospf *ospf;
+
        /* vrf name provided call inst and name based api
         * in case of no name pass default ospf instance */
        if (name)
@@ -402,39 +491,7 @@ struct ospf *ospf_get(unsigned short instance, const char *name, bool *created)
                ospf = ospf_new(instance, name);
                ospf_add(ospf);
 
-               ospf_opaque_type11_lsa_init(ospf);
-
-               if (ospf->vrf_id != VRF_UNKNOWN)
-                       ospf->oi_running = 1;
-
-               /* Activate 'ip ospf area x' configured interfaces for given
-                * vrf. Activate area on vrf x aware interfaces.
-                * vrf_enable callback calls router_id_update which
-                * internally will call ospf_if_update to trigger
-                * network_run_state
-                */
-               vrf = vrf_lookup_by_id(ospf->vrf_id);
-
-               FOR_ALL_INTERFACES (vrf, ifp) {
-                       struct ospf_if_params *params;
-                       struct route_node *rn;
-                       uint32_t count = 0;
-
-                       params = IF_DEF_PARAMS(ifp);
-                       if (OSPF_IF_PARAM_CONFIGURED(params, if_area))
-                               count++;
-
-                       for (rn = route_top(IF_OIFS_PARAMS(ifp)); rn; rn = route_next(rn))
-                               if ((params = rn->info) && OSPF_IF_PARAM_CONFIGURED(params, if_area))
-                                       count++;
-
-                       if (count > 0) {
-                               ospf_interface_area_set(ospf, ifp);
-                               ospf->if_ospf_cli_count += count;
-                       }
-               }
-
-               ospf_router_id_update(ospf);
+               ospf_init(ospf);
        }
 
        return ospf;
@@ -450,7 +507,7 @@ struct ospf *ospf_get_instance(unsigned short instance, bool *created)
                ospf = ospf_new(instance, NULL /* VRF_DEFAULT*/);
                ospf_add(ospf);
 
-               ospf_opaque_type11_lsa_init(ospf);
+               ospf_init(ospf);
        }
 
        return ospf;
@@ -864,14 +921,11 @@ static struct ospf_area *ospf_area_new(struct ospf *ospf,
        return new;
 }
 
-static void ospf_area_free(struct ospf_area *area)
+void ospf_area_lsdb_discard_delete(struct ospf_area *area)
 {
        struct route_node *rn;
        struct ospf_lsa *lsa;
 
-       ospf_opaque_type10_lsa_term(area);
-
-       /* Free LSDBs. */
        LSDB_LOOP (ROUTER_LSDB(area), rn, lsa)
                ospf_discard_from_db(area->ospf, area->lsdb, lsa);
        LSDB_LOOP (NETWORK_LSDB(area), rn, lsa)
@@ -889,6 +943,15 @@ static void ospf_area_free(struct ospf_area *area)
                ospf_discard_from_db(area->ospf, area->lsdb, lsa);
 
        ospf_lsdb_delete_all(area->lsdb);
+}
+
+static void ospf_area_free(struct ospf_area *area)
+{
+       ospf_opaque_type10_lsa_term(area);
+
+       /* Free LSDBs. */
+       ospf_area_lsdb_discard_delete(area);
+
        ospf_lsdb_free(area->lsdb);
 
        ospf_lsa_unlock(&area->router_lsa_self);
@@ -1603,7 +1666,8 @@ int ospf_area_nssa_unset(struct ospf *ospf, struct in_addr area_id, int argc)
                        OSPF_NSSA_TRANS_STABLE_DEFAULT;
                ospf_area_type_set(area, OSPF_AREA_DEFAULT);
        } else {
-               area->NSSATranslatorRole = OSPF_NSSA_ROLE_CANDIDATE;
+               ospf_area_nssa_translator_role_set(ospf, area_id,
+                                                  OSPF_NSSA_ROLE_CANDIDATE);
        }
 
        ospf_area_check_free(ospf, area_id);
@@ -1620,7 +1684,19 @@ int ospf_area_nssa_translator_role_set(struct ospf *ospf,
        if (area == NULL)
                return 0;
 
-       area->NSSATranslatorRole = role;
+       if (role != area->NSSATranslatorRole) {
+               if ((area->NSSATranslatorRole == OSPF_NSSA_ROLE_ALWAYS)
+                   || (role == OSPF_NSSA_ROLE_ALWAYS)) {
+                       /* RFC 3101 3.1
+                        * if new role is OSPF_NSSA_ROLE_ALWAYS we need to set
+                        * Nt bit, if the role was OSPF_NSSA_ROLE_ALWAYS we need
+                        * to clear Nt bit
+                        */
+                       area->NSSATranslatorRole = role;
+                       ospf_router_lsa_update_area(area);
+               } else
+                       area->NSSATranslatorRole = role;
+       }
 
        return 1;
 }
index bdd09e1e766cb15398d4b3400ffcd608529ac25f..6960d151c2213fd4a7011657eddf4845095eb979 100644 (file)
@@ -303,7 +303,7 @@ struct ospf {
        uint32_t rx_lsa_count;
 
        /* Counter of "ip ospf area x.x.x.x" used
-        * for multual exclusion of network command under
+        * for mutual exclusion of network command under
         * router ospf or ip ospf area x under interface. */
        uint32_t if_ospf_cli_count;
 
@@ -571,7 +571,11 @@ extern struct ospf *ospf_lookup_by_inst_name(unsigned short instance,
                                             const char *name);
 extern struct ospf *ospf_lookup_by_vrf_id(vrf_id_t vrf_id);
 extern void ospf_finish(struct ospf *);
+extern void ospf_process_refresh_data(struct ospf *ospf, bool reset);
 extern void ospf_router_id_update(struct ospf *ospf);
+extern void ospf_process_reset(struct ospf *ospf);
+extern void ospf_neighbor_reset(struct ospf *ospf, struct in_addr nbr_id,
+                               const char *nbr_str);
 extern int ospf_network_set(struct ospf *, struct prefix_ipv4 *, struct in_addr,
                            int);
 extern int ospf_network_unset(struct ospf *, struct prefix_ipv4 *,
@@ -596,6 +600,7 @@ extern int ospf_area_shortcut_set(struct ospf *, struct ospf_area *, int);
 extern int ospf_area_shortcut_unset(struct ospf *, struct ospf_area *);
 extern int ospf_timers_refresh_set(struct ospf *, int);
 extern int ospf_timers_refresh_unset(struct ospf *);
+void ospf_area_lsdb_discard_delete(struct ospf_area *area);
 extern int ospf_nbr_nbma_set(struct ospf *, struct in_addr);
 extern int ospf_nbr_nbma_unset(struct ospf *, struct in_addr);
 extern int ospf_nbr_nbma_priority_set(struct ospf *, struct in_addr, uint8_t);
@@ -604,7 +609,6 @@ extern int ospf_nbr_nbma_poll_interval_set(struct ospf *, struct in_addr,
                                           unsigned int);
 extern int ospf_nbr_nbma_poll_interval_unset(struct ospf *, struct in_addr);
 extern void ospf_prefix_list_update(struct prefix_list *);
-extern void ospf_init(void);
 extern void ospf_if_update(struct ospf *, struct interface *);
 extern void ospf_ls_upd_queue_empty(struct ospf_interface *);
 extern void ospf_terminate(void);
diff --git a/pathd/.gitignore b/pathd/.gitignore
new file mode 100644 (file)
index 0000000..95f4a99
--- /dev/null
@@ -0,0 +1,2 @@
+libpath.a
+pathd
diff --git a/pathd/Makefile b/pathd/Makefile
new file mode 100644 (file)
index 0000000..b681a9a
--- /dev/null
@@ -0,0 +1,10 @@
+all: ALWAYS
+       @$(MAKE) -s -C .. pathd/pathd
+%: ALWAYS
+       @$(MAKE) -s -C .. pathd/$@
+
+Makefile:
+       #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/pathd/path_cli.c b/pathd/path_cli.c
new file mode 100644 (file)
index 0000000..8beb428
--- /dev/null
@@ -0,0 +1,1108 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#include <float.h>
+#include <math.h>
+#include <zebra.h>
+
+#include "log.h"
+#include "command.h"
+#include "mpls.h"
+#include "northbound_cli.h"
+#include "termtable.h"
+
+#include "pathd/pathd.h"
+#include "pathd/path_nb.h"
+#include "pathd/path_memory.h"
+#ifndef VTYSH_EXTRACT_PL
+#include "pathd/path_cli_clippy.c"
+#endif
+
+#define XPATH_MAXATTRSIZE 64
+#define XPATH_MAXKEYSIZE 42
+#define XPATH_POLICY_BASELEN 100
+#define XPATH_POLICY_MAXLEN (XPATH_POLICY_BASELEN + XPATH_MAXATTRSIZE)
+#define XPATH_CANDIDATE_BASELEN (XPATH_POLICY_BASELEN + XPATH_MAXKEYSIZE)
+#define XPATH_CANDIDATE_MAXLEN (XPATH_CANDIDATE_BASELEN + XPATH_MAXATTRSIZE)
+
+
+static int config_write_segment_routing(struct vty *vty);
+static int config_write_traffic_eng(struct vty *vty);
+static int config_write_segment_lists(struct vty *vty);
+static int config_write_sr_policies(struct vty *vty);
+
+DEFINE_MTYPE_STATIC(PATHD, PATH_CLI, "Client")
+
+/* Vty node structures. */
+static struct cmd_node segment_routing_node = {
+       .name = "segment-routing",
+       .node = SEGMENT_ROUTING_NODE,
+       .parent_node = CONFIG_NODE,
+       .prompt = "%s(config-sr)# ",
+       .config_write = config_write_segment_routing,
+};
+
+static struct cmd_node sr_traffic_eng_node = {
+       .name = "sr traffic-eng",
+       .node = SR_TRAFFIC_ENG_NODE,
+       .parent_node = SEGMENT_ROUTING_NODE,
+       .prompt = "%s(config-sr-te)# ",
+       .config_write = config_write_traffic_eng,
+};
+
+static struct cmd_node srte_segment_list_node = {
+       .name = "srte segment-list",
+       .node = SR_SEGMENT_LIST_NODE,
+       .parent_node = SR_TRAFFIC_ENG_NODE,
+       .prompt = "%s(config-sr-te-segment-list)# ",
+       .config_write = config_write_segment_lists,
+};
+
+static struct cmd_node srte_policy_node = {
+       .name = "srte policy",
+       .node = SR_POLICY_NODE,
+       .parent_node = SR_TRAFFIC_ENG_NODE,
+       .prompt = "%s(config-sr-te-policy)# ",
+       .config_write = config_write_sr_policies,
+};
+
+static struct cmd_node srte_candidate_dyn_node = {
+       .name = "srte candidate-dyn",
+       .node = SR_CANDIDATE_DYN_NODE,
+       .parent_node = SR_POLICY_NODE,
+       .prompt = "%s(config-sr-te-candidate)# ",
+};
+
+
+/*
+ * Show SR-TE info
+ */
+DEFPY(show_srte_policy,
+      show_srte_policy_cmd,
+      "show sr-te policy",
+      SHOW_STR
+      "SR-TE info\n"
+      "SR-TE Policy\n")
+{
+       struct ttable *tt;
+       struct srte_policy *policy;
+       char *table;
+
+       if (RB_EMPTY(srte_policy_head, &srte_policies)) {
+               vty_out(vty, "No SR Policies to display.\n\n");
+               return CMD_SUCCESS;
+       }
+
+       /* Prepare table. */
+       tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+       ttable_add_row(tt, "Endpoint|Color|Name|BSID|Status");
+       tt->style.cell.rpad = 2;
+       tt->style.corner = '+';
+       ttable_restyle(tt);
+       ttable_rowseps(tt, 0, BOTTOM, true, '-');
+
+       RB_FOREACH (policy, srte_policy_head, &srte_policies) {
+               char endpoint[46];
+               char binding_sid[16] = "-";
+
+               ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
+               if (policy->binding_sid != MPLS_LABEL_NONE)
+                       snprintf(binding_sid, sizeof(binding_sid), "%u",
+                                policy->binding_sid);
+
+               ttable_add_row(tt, "%s|%u|%s|%s|%s", endpoint, policy->color,
+                              policy->name, binding_sid,
+                              policy->status == SRTE_POLICY_STATUS_UP
+                                      ? "Active"
+                                      : "Inactive");
+       }
+
+       /* Dump the generated table. */
+       table = ttable_dump(tt, "\n");
+       vty_out(vty, "%s\n", table);
+       XFREE(MTYPE_TMP, table);
+
+       ttable_del(tt);
+
+       return CMD_SUCCESS;
+}
+
+/*
+ * Show detailed SR-TE info
+ */
+DEFPY(show_srte_policy_detail,
+      show_srte_policy_detail_cmd,
+      "show sr-te policy detail",
+      SHOW_STR
+      "SR-TE info\n"
+      "SR-TE Policy\n"
+      "Show a detailed summary\n")
+{
+       struct srte_policy *policy;
+
+       if (RB_EMPTY(srte_policy_head, &srte_policies)) {
+               vty_out(vty, "No SR Policies to display.\n\n");
+               return CMD_SUCCESS;
+       }
+
+       vty_out(vty, "\n");
+       RB_FOREACH (policy, srte_policy_head, &srte_policies) {
+               struct srte_candidate *candidate;
+               char endpoint[46];
+               char binding_sid[16] = "-";
+               char *segment_list_info;
+               static char undefined_info[] = "(undefined)";
+               static char created_by_pce_info[] = "(created by PCE)";
+
+
+               ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
+               if (policy->binding_sid != MPLS_LABEL_NONE)
+                       snprintf(binding_sid, sizeof(binding_sid), "%u",
+                                policy->binding_sid);
+               vty_out(vty,
+                       "Endpoint: %s  Color: %u  Name: %s  BSID: %s  Status: %s\n",
+                       endpoint, policy->color, policy->name, binding_sid,
+                       policy->status == SRTE_POLICY_STATUS_UP ? "Active"
+                                                               : "Inactive");
+
+               RB_FOREACH (candidate, srte_candidate_head,
+                           &policy->candidate_paths) {
+                       struct srte_segment_list *segment_list;
+
+                       segment_list = candidate->lsp->segment_list;
+                       if (segment_list == NULL)
+                               segment_list_info = undefined_info;
+                       else if (segment_list->protocol_origin
+                                == SRTE_ORIGIN_PCEP)
+                               segment_list_info = created_by_pce_info;
+                       else
+                               segment_list_info =
+                                       candidate->lsp->segment_list->name;
+
+                       vty_out(vty,
+                               "  %s Preference: %d  Name: %s  Type: %s  Segment-List: %s  Protocol-Origin: %s\n",
+                               CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST)
+                                       ? "*"
+                                       : " ",
+                               candidate->preference, candidate->name,
+                               candidate->type == SRTE_CANDIDATE_TYPE_EXPLICIT
+                                       ? "explicit"
+                                       : "dynamic",
+                               segment_list_info,
+                               srte_origin2str(
+                                       candidate->lsp->protocol_origin));
+               }
+
+               vty_out(vty, "\n");
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFPY_NOSH(
+      segment_routing_list,
+      segment_routing_cmd,
+      "segment-routing",
+      "Configure segment routing\n")
+{
+       VTY_PUSH_CONTEXT_NULL(SEGMENT_ROUTING_NODE);
+       return CMD_SUCCESS;
+}
+
+DEFPY_NOSH(
+      sr_traffic_eng_list,
+      sr_traffic_eng_cmd,
+      "traffic-eng",
+      "Configure SR traffic engineering\n")
+{
+       VTY_PUSH_CONTEXT_NULL(SR_TRAFFIC_ENG_NODE);
+       return CMD_SUCCESS;
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/segment-list
+ */
+DEFPY_NOSH(
+      srte_segment_list,
+      srte_segment_list_cmd,
+      "segment-list WORD$name",
+      "Segment List\n"
+      "Segment List Name\n")
+{
+       char xpath[XPATH_MAXLEN];
+       int ret;
+
+       snprintf(xpath, sizeof(xpath),
+                "/frr-pathd:pathd/srte/segment-list[name='%s']", name);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+       snprintf(xpath, sizeof(xpath),
+                "/frr-pathd:pathd/srte/segment-list[name='%s']/protocol-origin",
+                name);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "local");
+
+       snprintf(xpath, sizeof(xpath),
+                "/frr-pathd:pathd/srte/segment-list[name='%s']/originator", name);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "config");
+
+       ret = nb_cli_apply_changes(vty, NULL);
+       if (ret == CMD_SUCCESS) {
+               snprintf(xpath, sizeof(xpath),
+                        "/frr-pathd:pathd/srte/segment-list[name='%s']", name);
+               VTY_PUSH_XPATH(SR_SEGMENT_LIST_NODE, xpath);
+       }
+
+       return ret;
+}
+
+DEFPY(srte_no_segment_list,
+      srte_no_segment_list_cmd,
+      "no segment-list WORD$name",
+      NO_STR
+      "Segment List\n"
+      "Segment List Name\n")
+{
+       char xpath[XPATH_MAXLEN];
+
+       snprintf(xpath, sizeof(xpath),
+                "/frr-pathd:pathd/srte/segment-list[name='%s']", name);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_srte_segment_list(struct vty *vty, struct lyd_node *dnode,
+                               bool show_defaults)
+{
+       vty_out(vty, "  segment-list %s\n",
+               yang_dnode_get_string(dnode, "./name"));
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/segment-list/segment
+ */
+DEFPY(srte_segment_list_segment,
+      srte_segment_list_segment_cmd,
+      "index (0-4294967295)$index mpls label (16-1048575)$label "
+      "[nai$has_nai <"
+      "node <A.B.C.D$node_ipv4|X:X::X:X$node_ipv6>"
+      ">]",
+      "Index\n"
+      "Index Value\n"
+      "MPLS or IP Label\n"
+      "Label\n"
+      "Label Value\n"
+      "Segment NAI\n"
+      "NAI node identifier\n"
+      "NAI IPv4 node identifier\n"
+      "NAI IPv6 node identifier\n")
+{
+       char xpath[XPATH_MAXLEN];
+       const char *node_id;
+
+       snprintf(xpath, sizeof(xpath), "./segment[index='%s']", index_str);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+       snprintf(xpath, sizeof(xpath), "./segment[index='%s']/sid-value",
+                index_str);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, label_str);
+
+       if (has_nai != NULL) {
+               snprintf(xpath, sizeof(xpath), "./segment[index='%s']/nai/type",
+                        index_str);
+               if (node_ipv4_str != NULL) {
+                       nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
+                                             "ipv4_node");
+                       node_id = node_ipv4_str;
+               } else if (node_ipv6_str != NULL) {
+                       nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
+                                             "ipv6_node");
+                       node_id = node_ipv6_str;
+               } else {
+                       return CMD_ERR_NO_MATCH;
+               }
+               snprintf(xpath, sizeof(xpath),
+                        "./segment[index='%s']/nai/local-address", index_str);
+               nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, node_id);
+       } else {
+               snprintf(xpath, sizeof(xpath), "./segment[index='%s']/nai",
+                        index_str);
+               nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+       }
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(srte_segment_list_no_segment,
+      srte_segment_list_no_segment_cmd,
+      "no index (0-4294967295)$index",
+      NO_STR
+      "Index\n"
+      "Index Value\n")
+{
+       char xpath[XPATH_MAXLEN];
+
+       snprintf(xpath, sizeof(xpath), "./segment[index='%s']", index_str);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_srte_segment_list_segment(struct vty *vty,
+                                       struct lyd_node *dnode,
+                                       bool show_defaults)
+{
+       vty_out(vty, "   index %s mpls label %s",
+               yang_dnode_get_string(dnode, "./index"),
+               yang_dnode_get_string(dnode, "./sid-value"));
+       if (yang_dnode_exists(dnode, "./nai")) {
+               struct ipaddr addr;
+               switch (yang_dnode_get_enum(dnode, "./nai/type")) {
+               case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
+                       yang_dnode_get_ip(&addr, dnode, "./nai/local-address");
+                       vty_out(vty, " nai node %pI4", &addr.ipaddr_v4);
+                       break;
+               case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
+                       yang_dnode_get_ip(&addr, dnode, "./nai/local-address");
+                       vty_out(vty, " nai node %pI6", &addr.ipaddr_v6);
+                       break;
+               default:
+                       break;
+               }
+       }
+       vty_out(vty, "\n");
+}
+
+/*
+ * XPath: /frr-pathd:pathd/policy
+ */
+DEFPY_NOSH(
+       srte_policy,
+       srte_policy_cmd,
+       "policy color (0-4294967295)$num endpoint <A.B.C.D|X:X::X:X>$endpoint",
+       "Segment Routing Policy\n"
+       "SR Policy color\n"
+       "SR Policy color value\n"
+       "SR Policy endpoint\n"
+       "SR Policy endpoint IPv4 address\n"
+       "SR Policy endpoint IPv6 address\n")
+{
+       char xpath[XPATH_POLICY_BASELEN];
+       int ret;
+
+       snprintf(xpath, sizeof(xpath),
+                "/frr-pathd:pathd/srte/policy[color='%s'][endpoint='%s']",
+                num_str, endpoint_str);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+       ret = nb_cli_apply_changes(vty, NULL);
+       if (ret == CMD_SUCCESS)
+               VTY_PUSH_XPATH(SR_POLICY_NODE, xpath);
+
+       return ret;
+}
+
+DEFPY(srte_no_policy,
+      srte_no_policy_cmd,
+      "no policy color (0-4294967295)$num endpoint <A.B.C.D|X:X::X:X>$endpoint",
+      NO_STR
+      "Segment Routing Policy\n"
+      "SR Policy color\n"
+      "SR Policy color value\n"
+      "SR Policy endpoint\n"
+      "SR Policy endpoint IPv4 address\n"
+      "SR Policy endpoint IPv6 address\n")
+{
+       char xpath[XPATH_POLICY_BASELEN];
+
+       snprintf(xpath, sizeof(xpath),
+                "/frr-pathd:pathd/srte/policy[color='%s'][endpoint='%s']",
+                num_str, endpoint_str);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_srte_policy(struct vty *vty, struct lyd_node *dnode,
+                         bool show_defaults)
+{
+       vty_out(vty, "  policy color %s endpoint %s\n",
+               yang_dnode_get_string(dnode, "./color"),
+               yang_dnode_get_string(dnode, "./endpoint"));
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/name
+ */
+DEFPY(srte_policy_name,
+      srte_policy_name_cmd,
+      "name WORD$name",
+      "Segment Routing Policy name\n"
+      "SR Policy name value\n")
+{
+       nb_cli_enqueue_change(vty, "./name", NB_OP_CREATE, name);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(srte_policy_no_name,
+      srte_policy_no_name_cmd,
+      "no name [WORD]",
+      NO_STR
+      "Segment Routing Policy name\n"
+      "SR Policy name value\n")
+{
+       nb_cli_enqueue_change(vty, "./name", NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+
+void cli_show_srte_policy_name(struct vty *vty, struct lyd_node *dnode,
+                                    bool show_defaults)
+{
+       vty_out(vty, "   name %s\n", yang_dnode_get_string(dnode, NULL));
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/binding-sid
+ */
+DEFPY(srte_policy_binding_sid,
+      srte_policy_binding_sid_cmd,
+      "binding-sid (16-1048575)$label",
+      "Segment Routing Policy Binding-SID\n"
+      "SR Policy Binding-SID label\n")
+{
+       nb_cli_enqueue_change(vty, "./binding-sid", NB_OP_CREATE, label_str);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(srte_policy_no_binding_sid,
+      srte_policy_no_binding_sid_cmd,
+      "no binding-sid [(16-1048575)]",
+      NO_STR
+      "Segment Routing Policy Binding-SID\n"
+      "SR Policy Binding-SID label\n")
+{
+       nb_cli_enqueue_change(vty, "./binding-sid", NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_srte_policy_binding_sid(struct vty *vty,
+                                     struct lyd_node *dnode,
+                                     bool show_defaults)
+{
+       vty_out(vty, "   binding-sid %s\n", yang_dnode_get_string(dnode, NULL));
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/candidate-path
+ */
+DEFPY(srte_policy_candidate_exp,
+      srte_policy_candidate_exp_cmd,
+      "candidate-path preference (0-4294967295)$preference name WORD$name \
+        explicit segment-list WORD$list_name",
+      "Segment Routing Policy Candidate Path\n"
+      "Segment Routing Policy Candidate Path Preference\n"
+      "Administrative Preference\n"
+      "Segment Routing Policy Candidate Path Name\n"
+      "Symbolic Name\n"
+      "Explicit Path\n"
+      "List of SIDs\n"
+      "Name of the Segment List\n")
+{
+       nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, preference_str);
+       nb_cli_enqueue_change(vty, "./name", NB_OP_MODIFY, name);
+       nb_cli_enqueue_change(vty, "./protocol-origin", NB_OP_MODIFY, "local");
+       nb_cli_enqueue_change(vty, "./originator", NB_OP_MODIFY, "config");
+       nb_cli_enqueue_change(vty, "./type", NB_OP_MODIFY, "explicit");
+       nb_cli_enqueue_change(vty, "./segment-list-name", NB_OP_MODIFY,
+                             list_name);
+       return nb_cli_apply_changes(vty, "./candidate-path[preference='%s']",
+                                   preference_str);
+}
+
+DEFPY_NOSH(
+       srte_policy_candidate_dyn,
+       srte_policy_candidate_dyn_cmd,
+       "candidate-path preference (0-4294967295)$preference name WORD$name dynamic",
+       "Segment Routing Policy Candidate Path\n"
+       "Segment Routing Policy Candidate Path Preference\n"
+       "Administrative Preference\n"
+       "Segment Routing Policy Candidate Path Name\n"
+       "Symbolic Name\n"
+       "Dynamic Path\n")
+{
+       char xpath[XPATH_MAXLEN + XPATH_CANDIDATE_BASELEN];
+       int ret;
+
+       snprintf(xpath, sizeof(xpath), "%s/candidate-path[preference='%s']",
+                VTY_CURR_XPATH, preference_str);
+
+       nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, preference_str);
+       nb_cli_enqueue_change(vty, "./name", NB_OP_MODIFY, name);
+       nb_cli_enqueue_change(vty, "./protocol-origin", NB_OP_MODIFY, "local");
+       nb_cli_enqueue_change(vty, "./originator", NB_OP_MODIFY, "config");
+       nb_cli_enqueue_change(vty, "./type", NB_OP_MODIFY, "dynamic");
+       ret = nb_cli_apply_changes(vty, "./candidate-path[preference='%s']",
+                                  preference_str);
+
+       if (ret == CMD_SUCCESS)
+               VTY_PUSH_XPATH(SR_CANDIDATE_DYN_NODE, xpath);
+
+       return ret;
+}
+
+DEFPY(srte_candidate_bandwidth,
+      srte_candidate_bandwidth_cmd,
+      "bandwidth BANDWIDTH$value [required$required]",
+      "Define a bandwidth constraint\n"
+      "Bandwidth value\n"
+      "Required constraint\n")
+{
+       nb_cli_enqueue_change(vty, "./constraints/bandwidth/required",
+                             NB_OP_MODIFY, required ? "true" : "false");
+       nb_cli_enqueue_change(vty, "./constraints/bandwidth/value",
+                             NB_OP_MODIFY, value);
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(srte_candidate_no_bandwidth,
+      srte_candidate_no_bandwidth_cmd,
+      "no bandwidth [BANDWIDTH$value] [required$required]",
+      NO_STR
+      "Remove a bandwidth constraint\n"
+      "Bandwidth value\n"
+      "Required constraint\n")
+{
+       nb_cli_enqueue_change(vty, "./constraints/bandwidth", NB_OP_DESTROY,
+                             NULL);
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(srte_candidate_affinity_filter,
+      srte_candidate_affinity_filter_cmd,
+      "affinity {exclude-any|include-any|include-all}$type BITPATTERN$value",
+      "Affinity constraint\n"
+      "Exclude any matching link\n"
+      "Include any matching link\n"
+      "Include all matching links\n"
+      "Attribute filter bit pattern as an hexadecimal value from 0x00000000 to 0xFFFFFFFF\n")
+{
+       uint32_t filter;
+       char xpath[XPATH_CANDIDATE_MAXLEN];
+       char decimal_value[11];
+
+       if (sscanf(value, "0x%x", &filter) != 1) {
+               vty_out(vty, "affinity type: fscanf: %s\n",
+                       safe_strerror(errno));
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+       snprintf(decimal_value, sizeof(decimal_value), "%u", filter);
+       snprintf(xpath, sizeof(xpath), "./constraints/affinity/%s", type);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, decimal_value);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(srte_candidate_no_affinity_filter,
+      srte_candidate_no_affinity_filter_cmd,
+      "no affinity {exclude-any|include-any|include-all}$type [BITPATTERN$value]",
+      NO_STR
+      "Affinity constraint\n"
+      "Exclude any matching link\n"
+      "Include any matching link\n"
+      "Include all matching links\n"
+      "Attribute filter bit pattern as an hexadecimal value from 0x00000000 to 0xFFFFFFFF\n")
+{
+       char xpath[XPATH_CANDIDATE_MAXLEN];
+
+       snprintf(xpath, sizeof(xpath), "./constraints/affinity/%s", type);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(srte_candidate_metric,
+      srte_candidate_metric_cmd,
+      "metric [bound$bound] <igp|te|hc|abc|lmll|cigp|cte|pigp|pte|phc|msd|pd|pdv|pl|ppd|ppdv|ppl|nap|nlp|dc|bnc>$type METRIC$value [required$required]",
+      "Define a metric constraint\n"
+      "If the metric is bounded\n"
+      "IGP metric\n"
+      "TE metric\n"
+      "Hop Counts\n"
+      "Aggregate bandwidth consumption\n"
+      "Load of the most loaded link\n"
+      "Cumulative IGP cost\n"
+      "Cumulative TE cost\n"
+      "P2MP IGP metric\n"
+      "P2MP TE metric\n"
+      "P2MP hop count metric\n"
+      "Segment-ID (SID) Depth.\n"
+      "Path Delay metric\n"
+      "Path Delay Variation metric\n"
+      "Path Loss metric\n"
+      "P2MP Path Delay metric\n"
+      "P2MP Path Delay variation metric\n"
+      "P2MP Path Loss metric\n"
+      "Number of adaptations on a path\n"
+      "Number of layers on a path\n"
+      "Domain Count metric\n"
+      "Border Node Count metric\n"
+      "Metric value\n"
+      "Required constraint\n")
+{
+       char xpath[XPATH_CANDIDATE_MAXLEN];
+       snprintf(xpath, sizeof(xpath), "./constraints/metrics[type='%s']/value",
+                type);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, value);
+       snprintf(xpath, sizeof(xpath),
+                "./constraints/metrics[type='%s']/is-bound", type);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
+                             (bound != NULL) ? "true" : "false");
+       snprintf(xpath, sizeof(xpath),
+                "./constraints/metrics[type='%s']/required", type);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
+                             required ? "true" : "false");
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(srte_candidate_no_metric,
+      srte_candidate_no_metric_cmd,
+      "no metric [bound] <igp|te|hc|abc|lmll|cigp|cte|pigp|pte|phc|msd|pd|pdv|pl|ppd|ppdv|ppl|nap|nlp|dc|bnc>$type [METRIC$value] [required$required]",
+      NO_STR
+      "Remove a metric constraint\n"
+      "If the metric is bounded\n"
+      "IGP metric\n"
+      "TE metric\n"
+      "Hop Counts\n"
+      "Aggregate bandwidth consumption\n"
+      "Load of the most loaded link\n"
+      "Cumulative IGP cost\n"
+      "Cumulative TE cost\n"
+      "P2MP IGP metric\n"
+      "P2MP TE metric\n"
+      "P2MP hop count metric\n"
+      "Segment-ID (SID) Depth.\n"
+      "Path Delay metric\n"
+      "Path Delay Variation metric\n"
+      "Path Loss metric\n"
+      "P2MP Path Delay metric\n"
+      "P2MP Path Delay variation metric\n"
+      "P2MP Path Loss metric\n"
+      "Number of adaptations on a path\n"
+      "Number of layers on a path\n"
+      "Domain Count metric\n"
+      "Border Node Count metric\n"
+      "Metric value\n"
+      "Required constraint\n")
+{
+       char xpath[XPATH_CANDIDATE_MAXLEN];
+       snprintf(xpath, sizeof(xpath), "./constraints/metrics[type='%s']",
+                type);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(srte_policy_no_candidate,
+      srte_policy_no_candidate_cmd,
+      "no candidate-path\
+       preference (0-4294967295)$preference\
+       [name WORD\
+       <\
+         explicit segment-list WORD\
+         |dynamic\
+       >]",
+      NO_STR
+      "Segment Routing Policy Candidate Path\n"
+      "Segment Routing Policy Candidate Path Preference\n"
+      "Administrative Preference\n"
+      "Segment Routing Policy Candidate Path Name\n"
+      "Symbolic Name\n"
+      "Explicit Path\n"
+      "List of SIDs\n"
+      "Name of the Segment List\n"
+      "Dynamic Path\n")
+{
+       nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, "./candidate-path[preference='%s']",
+                                   preference_str);
+}
+
+DEFPY(srte_candidate_objfun,
+      srte_candidate_objfun_cmd,
+      "objective-function <mcp|mlp|mbp|mbc|mll|mcc|spt|mct|mplp|mup|mrup|mtd|mbn|mctd|msl|mss|msn>$type [required$required]",
+      "Define an objective function constraint\n"
+      "Minimum Cost Path\n"
+      "Minimum Load Path\n"
+      "Maximum residual Bandwidth Path\n"
+      "Minimize aggregate Bandwidth Consumption\n"
+      "Minimize the Load of the most loaded Link\n"
+      "Minimize the Cumulative Cost of a set of paths\n"
+      "Shortest Path Tree\n"
+      "Minimum Cost Tree\n"
+      "Minimum Packet Loss Path\n"
+      "Maximum Under-Utilized Path\n"
+      "Maximum Reserved Under-Utilized Path\n"
+      "Minimize the number of Transit Domains\n"
+      "Minimize the number of Border Nodes\n"
+      "Minimize the number of Common Transit Domains\n"
+      "Minimize the number of Shared Links\n"
+      "Minimize the number of Shared SRLGs\n"
+      "Minimize the number of Shared Nodes\n"
+      "Required constraint\n")
+{
+       char xpath[XPATH_CANDIDATE_MAXLEN];
+       nb_cli_enqueue_change(vty, "./constraints/objective-function",
+                             NB_OP_DESTROY, NULL);
+       snprintf(xpath, sizeof(xpath),
+                "./constraints/objective-function/required");
+       nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
+                             required ? "true" : "false");
+       nb_cli_enqueue_change(vty, "./constraints/objective-function/type",
+                             NB_OP_MODIFY, type);
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(srte_candidate_no_objfun,
+      srte_candidate_no_objfun_cmd,
+      "no objective-function [<mcp|mlp|mbp|mbc|mll|mcc|spt|mct|mplp|mup|mrup|mtd|mbn|mctd|msl|mss|msn>] [required$required]",
+      NO_STR
+      "Remove an objective function constraint\n"
+      "Minimum Cost Path\n"
+      "Minimum Load Path\n"
+      "Maximum residual Bandwidth Path\n"
+      "Minimize aggregate Bandwidth Consumption\n"
+      "Minimize the Load of the most loaded Link\n"
+      "Minimize the Cumulative Cost of a set of paths\n"
+      "Shortest Path Tree\n"
+      "Minimum Cost Tree\n"
+      "Minimum Packet Loss Path\n"
+      "Maximum Under-Utilized Path\n"
+      "Maximum Reserved Under-Utilized Path\n"
+      "Minimize the number of Transit Domains\n"
+      "Minimize the number of Border Nodes\n"
+      "Minimize the number of Common Transit Domains\n"
+      "Minimize the number of Shared Links\n"
+      "Minimize the number of Shared SRLGs\n"
+      "Minimize the number of Shared Nodes\n"
+      "Required constraint\n")
+{
+       nb_cli_enqueue_change(vty, "./constraints/objective-function",
+                             NB_OP_DESTROY, NULL);
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+static const char *objfun_type_name(enum objfun_type type)
+{
+       switch (type) {
+       case OBJFUN_MCP:
+               return "mcp";
+       case OBJFUN_MLP:
+               return "mlp";
+       case OBJFUN_MBP:
+               return "mbp";
+       case OBJFUN_MBC:
+               return "mbc";
+       case OBJFUN_MLL:
+               return "mll";
+       case OBJFUN_MCC:
+               return "mcc";
+       case OBJFUN_SPT:
+               return "spt";
+       case OBJFUN_MCT:
+               return "mct";
+       case OBJFUN_MPLP:
+               return "mplp";
+       case OBJFUN_MUP:
+               return "mup";
+       case OBJFUN_MRUP:
+               return "mrup";
+       case OBJFUN_MTD:
+               return "mtd";
+       case OBJFUN_MBN:
+               return "mbn";
+       case OBJFUN_MCTD:
+               return "mctd";
+       case OBJFUN_MSL:
+               return "msl";
+       case OBJFUN_MSS:
+               return "mss";
+       case OBJFUN_MSN:
+               return "msn";
+       default:
+               return NULL;
+       }
+}
+
+DEFPY_NOSH(show_debugging_pathd, show_debugging_pathd_cmd,
+          "show debugging [pathd]",
+          SHOW_STR
+          "State of each debugging option\n"
+          "pathd module debugging\n")
+{
+       /* nothing to do here */
+       return CMD_SUCCESS;
+}
+
+static const char *metric_type_name(enum srte_candidate_metric_type type)
+{
+       switch (type) {
+       case SRTE_CANDIDATE_METRIC_TYPE_IGP:
+               return "igp";
+       case SRTE_CANDIDATE_METRIC_TYPE_TE:
+               return "te";
+       case SRTE_CANDIDATE_METRIC_TYPE_HC:
+               return "hc";
+       case SRTE_CANDIDATE_METRIC_TYPE_ABC:
+               return "abc";
+       case SRTE_CANDIDATE_METRIC_TYPE_LMLL:
+               return "lmll";
+       case SRTE_CANDIDATE_METRIC_TYPE_CIGP:
+               return "cigp";
+       case SRTE_CANDIDATE_METRIC_TYPE_CTE:
+               return "cte";
+       case SRTE_CANDIDATE_METRIC_TYPE_PIGP:
+               return "pigp";
+       case SRTE_CANDIDATE_METRIC_TYPE_PTE:
+               return "pte";
+       case SRTE_CANDIDATE_METRIC_TYPE_PHC:
+               return "phc";
+       case SRTE_CANDIDATE_METRIC_TYPE_MSD:
+               return "msd";
+       case SRTE_CANDIDATE_METRIC_TYPE_PD:
+               return "pd";
+       case SRTE_CANDIDATE_METRIC_TYPE_PDV:
+               return "pdv";
+       case SRTE_CANDIDATE_METRIC_TYPE_PL:
+               return "pl";
+       case SRTE_CANDIDATE_METRIC_TYPE_PPD:
+               return "ppd";
+       case SRTE_CANDIDATE_METRIC_TYPE_PPDV:
+               return "ppdv";
+       case SRTE_CANDIDATE_METRIC_TYPE_PPL:
+               return "ppl";
+       case SRTE_CANDIDATE_METRIC_TYPE_NAP:
+               return "nap";
+       case SRTE_CANDIDATE_METRIC_TYPE_NLP:
+               return "nlp";
+       case SRTE_CANDIDATE_METRIC_TYPE_DC:
+               return "dc";
+       case SRTE_CANDIDATE_METRIC_TYPE_BNC:
+               return "bnc";
+       default:
+               return NULL;
+       }
+}
+
+static void config_write_float(struct vty *vty, float value)
+{
+       if (fabs(truncf(value) - value) < FLT_EPSILON) {
+               vty_out(vty, " %d", (int)value);
+               return;
+       } else {
+               vty_out(vty, " %f", value);
+       }
+}
+
+static void config_write_metric(struct vty *vty,
+                               enum srte_candidate_metric_type type,
+                               float value, bool required, bool is_bound)
+{
+       const char *name = metric_type_name(type);
+       if (name == NULL)
+               return;
+       vty_out(vty, "    metric %s%s", is_bound ? "bound " : "",
+               metric_type_name(type));
+       config_write_float(vty, value);
+       vty_out(vty, required ? " required" : "");
+       vty_out(vty, "\n");
+}
+
+static int config_write_metric_cb(const struct lyd_node *dnode, void *arg)
+{
+       struct vty *vty = arg;
+       enum srte_candidate_metric_type type;
+       bool required, is_bound = false;
+       float value;
+
+       type = yang_dnode_get_enum(dnode, "./type");
+       value = (float)yang_dnode_get_dec64(dnode, "./value");
+       required = yang_dnode_get_bool(dnode, "./required");
+       if (yang_dnode_exists(dnode, "./is-bound"))
+               is_bound = yang_dnode_get_bool(dnode, "./is-bound");
+
+       config_write_metric(vty, type, value, required, is_bound);
+       return YANG_ITER_CONTINUE;
+}
+
+void cli_show_srte_policy_candidate_path(struct vty *vty,
+                                        struct lyd_node *dnode,
+                                        bool show_defaults)
+{
+       float bandwidth;
+       uint32_t affinity;
+       bool required;
+       enum objfun_type objfun_type;
+       const char *type = yang_dnode_get_string(dnode, "./type");
+
+       vty_out(vty, "   candidate-path preference %s name %s %s",
+               yang_dnode_get_string(dnode, "./preference"),
+               yang_dnode_get_string(dnode, "./name"), type);
+       if (strmatch(type, "explicit"))
+               vty_out(vty, " segment-list %s",
+                       yang_dnode_get_string(dnode, "./segment-list-name"));
+       vty_out(vty, "\n");
+
+       if (strmatch(type, "dynamic")) {
+               if (yang_dnode_exists(dnode, "./constraints/bandwidth")) {
+                       bandwidth = (float)yang_dnode_get_dec64(
+                               dnode, "./constraints/bandwidth/value");
+                       required = yang_dnode_get_bool(
+                               dnode, "./constraints/bandwidth/required");
+                       vty_out(vty, "    %sbandwidth",
+                               required ? "required " : "");
+                       config_write_float(vty, bandwidth);
+                       vty_out(vty, "\n");
+               }
+               if (yang_dnode_exists(dnode,
+                                     "./constraints/affinity/exclude-any")) {
+                       affinity = yang_dnode_get_uint32(
+                               dnode, "./constraints/affinity/exclude-any");
+                       vty_out(vty, "    affinity exclude-any 0x%08x\n",
+                               affinity);
+               }
+               if (yang_dnode_exists(dnode,
+                                     "./constraints/affinity/include-any")) {
+                       affinity = yang_dnode_get_uint32(
+                               dnode, "./constraints/affinity/include-any");
+                       vty_out(vty, "    affinity include-any 0x%08x\n",
+                               affinity);
+               }
+               if (yang_dnode_exists(dnode,
+                                     "./constraints/affinity/include-all")) {
+                       affinity = yang_dnode_get_uint32(
+                               dnode, "./constraints/affinity/include-all");
+                       vty_out(vty, "    affinity include-all 0x%08x\n",
+                               affinity);
+               }
+               yang_dnode_iterate(config_write_metric_cb, vty, dnode,
+                                  "./constraints/metrics");
+               if (yang_dnode_exists(dnode,
+                                     "./constraints/objective-function")) {
+                       objfun_type = yang_dnode_get_enum(dnode,
+                               "./constraints/objective-function/type");
+                       required = yang_dnode_get_bool(dnode,
+                               "./constraints/objective-function/required");
+                       vty_out(vty, "    objective-function %s%s\n",
+                               objfun_type_name(objfun_type),
+                               required ? " required" : "");
+               }
+       }
+}
+
+static int config_write_dnode(const struct lyd_node *dnode, void *arg)
+{
+       struct vty *vty = arg;
+
+       nb_cli_show_dnode_cmds(vty, (struct lyd_node *)dnode, false);
+
+       return YANG_ITER_CONTINUE;
+}
+
+int config_write_segment_routing(struct vty *vty)
+{
+       vty_out(vty, "segment-routing\n");
+       return 1;
+}
+
+int config_write_traffic_eng(struct vty *vty)
+{
+       vty_out(vty, " traffic-eng\n");
+       return 1;
+}
+
+int config_write_segment_lists(struct vty *vty)
+{
+       yang_dnode_iterate(config_write_dnode, vty, running_config->dnode,
+                          "/frr-pathd:pathd/srte/segment-list");
+
+       return 1;
+}
+
+int config_write_sr_policies(struct vty *vty)
+{
+       yang_dnode_iterate(config_write_dnode, vty, running_config->dnode,
+                          "/frr-pathd:pathd/srte/policy");
+
+       return 1;
+}
+
+void path_cli_init(void)
+{
+       install_node(&segment_routing_node);
+       install_node(&sr_traffic_eng_node);
+       install_node(&srte_segment_list_node);
+       install_node(&srte_policy_node);
+       install_node(&srte_candidate_dyn_node);
+       install_default(SEGMENT_ROUTING_NODE);
+       install_default(SR_TRAFFIC_ENG_NODE);
+       install_default(SR_SEGMENT_LIST_NODE);
+       install_default(SR_POLICY_NODE);
+       install_default(SR_CANDIDATE_DYN_NODE);
+
+       install_element(ENABLE_NODE, &show_debugging_pathd_cmd);
+       install_element(ENABLE_NODE, &show_srte_policy_cmd);
+       install_element(ENABLE_NODE, &show_srte_policy_detail_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);
+       install_element(SR_TRAFFIC_ENG_NODE, &srte_no_segment_list_cmd);
+       install_element(SR_SEGMENT_LIST_NODE,
+                       &srte_segment_list_segment_cmd);
+       install_element(SR_SEGMENT_LIST_NODE,
+                       &srte_segment_list_no_segment_cmd);
+       install_element(SR_TRAFFIC_ENG_NODE, &srte_policy_cmd);
+       install_element(SR_TRAFFIC_ENG_NODE, &srte_no_policy_cmd);
+       install_element(SR_POLICY_NODE, &srte_policy_name_cmd);
+       install_element(SR_POLICY_NODE, &srte_policy_no_name_cmd);
+       install_element(SR_POLICY_NODE, &srte_policy_binding_sid_cmd);
+       install_element(SR_POLICY_NODE, &srte_policy_no_binding_sid_cmd);
+       install_element(SR_POLICY_NODE, &srte_policy_candidate_exp_cmd);
+       install_element(SR_POLICY_NODE, &srte_policy_candidate_dyn_cmd);
+       install_element(SR_POLICY_NODE, &srte_policy_no_candidate_cmd);
+       install_element(SR_CANDIDATE_DYN_NODE,
+                       &srte_candidate_bandwidth_cmd);
+       install_element(SR_CANDIDATE_DYN_NODE,
+                       &srte_candidate_no_bandwidth_cmd);
+       install_element(SR_CANDIDATE_DYN_NODE,
+                       &srte_candidate_affinity_filter_cmd);
+       install_element(SR_CANDIDATE_DYN_NODE,
+                       &srte_candidate_no_affinity_filter_cmd);
+       install_element(SR_CANDIDATE_DYN_NODE,
+                       &srte_candidate_metric_cmd);
+       install_element(SR_CANDIDATE_DYN_NODE,
+                       &srte_candidate_no_metric_cmd);
+       install_element(SR_CANDIDATE_DYN_NODE,
+                       &srte_candidate_objfun_cmd);
+       install_element(SR_CANDIDATE_DYN_NODE,
+                       &srte_candidate_no_objfun_cmd);
+}
diff --git a/pathd/path_debug.c b/pathd/path_debug.c
new file mode 100644 (file)
index 0000000..df05507
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#include <string.h>
+#include <stdbool.h>
+#include <time.h>
+#include <libyang/libyang.h>
+
+#include "printfrr.h"
+#include "ipaddr.h"
+
+#include "pathd/path_debug.h"
+
+THREAD_DATA char _debug_buff[DEBUG_BUFF_SIZE];
+
+/**
+ * Gives the string representation of an srte_protocol_origin enum value.
+ *
+ * @param origin The enum value to convert to string
+ * @return a constant string representation of the enum value
+ */
+const char *srte_protocol_origin_name(enum srte_protocol_origin origin)
+{
+       switch (origin) {
+       case SRTE_ORIGIN_UNDEFINED:
+               return "UNDEFINED";
+       case SRTE_ORIGIN_PCEP:
+               return "PCEP";
+       case SRTE_ORIGIN_BGP:
+               return "BGP";
+       case SRTE_ORIGIN_LOCAL:
+               return "LOCAL";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+/**
+ * Gives the string representation of an srte_candidate_type enum value.
+ *
+ * @param origin The enum value to convert to string
+ * @return a constant string representation of the enum value
+ */
+const char *srte_candidate_type_name(enum srte_candidate_type type)
+{
+       switch (type) {
+       case SRTE_CANDIDATE_TYPE_EXPLICIT:
+               return "EXPLICIT";
+       case SRTE_CANDIDATE_TYPE_DYNAMIC:
+               return "DYNAMIC";
+       case SRTE_CANDIDATE_TYPE_UNDEFINED:
+               return "UNDEFINED";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+/**
+ * Gives the string representation of an objfun_type enum value.
+ *
+ * @param origin The enum value to convert to string
+ * @return a constant string representation of the enum value
+ */
+const char *objfun_type_name(enum objfun_type type)
+{
+       switch (type) {
+       case OBJFUN_UNDEFINED:
+               return "UNDEFINED";
+       case OBJFUN_MCP:
+               return "MCP";
+       case OBJFUN_MLP:
+               return "MLP";
+       case OBJFUN_MBP:
+               return "MBP";
+       case OBJFUN_MBC:
+               return "MBC";
+       case OBJFUN_MLL:
+               return "MLL";
+       case OBJFUN_MCC:
+               return "MCC";
+       case OBJFUN_SPT:
+               return "SPT";
+       case OBJFUN_MCT:
+               return "MCT";
+       case OBJFUN_MPLP:
+               return "MPLP";
+       case OBJFUN_MUP:
+               return "MUP";
+       case OBJFUN_MRUP:
+               return "MRUP";
+       case OBJFUN_MTD:
+               return "MTD";
+       case OBJFUN_MBN:
+               return "MBN";
+       case OBJFUN_MCTD:
+               return "MCTD";
+       case OBJFUN_MSL:
+               return "MSL";
+       case OBJFUN_MSS:
+               return "MSS";
+       case OBJFUN_MSN:
+               return "MSN";
+       default:
+               return "UNKNOWN";
+       }
+}
diff --git a/pathd/path_debug.h b/pathd/path_debug.h
new file mode 100644 (file)
index 0000000..d9cfcb6
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#ifndef _PATH_DEBUG_H_
+#define _PATH_DEBUG_H_
+
+#include "pathd/pathd.h"
+
+#ifdef __GNUC__
+#define THREAD_DATA __thread
+#else
+#define THREAD_DATA
+#endif
+
+#define DEBUG_IDENT_SIZE 4
+#define DEBUG_BUFF_SIZE 4096
+#define TUP(A, B) ((((uint32_t)(A)) << 16) | ((uint32_t)(B)))
+#define PATHD_FORMAT_INIT() _debug_buff[0] = 0
+#define PATHD_FORMAT(fmt, ...)                                                 \
+       csnprintfrr(_debug_buff, DEBUG_BUFF_SIZE, fmt, ##__VA_ARGS__)
+#define PATHD_FORMAT_FINI() _debug_buff
+
+extern THREAD_DATA char _debug_buff[DEBUG_BUFF_SIZE];
+
+const char *srte_protocol_origin_name(enum srte_protocol_origin origin);
+const char *srte_candidate_type_name(enum srte_candidate_type type);
+const char *objfun_type_name(enum objfun_type type);
+
+#endif // _PATH_DEBUG_H_
\ No newline at end of file
diff --git a/pathd/path_errors.c b/pathd/path_errors.c
new file mode 100644 (file)
index 0000000..f8560a8
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * pathd-specific error messages.
+ * Copyright (C) 2020  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
+ */
+
+#include <zebra.h>
+
+#include "lib/ferr.h"
+#include "path_errors.h"
+
+/* clang-format off */
+static struct log_ref ferr_path_err[] = {
+       {
+               .code = EC_PATH_SYSTEM_CALL,
+               .title = "Thread setup error",
+               .description = "A system call for creating, or setting up PCEP module's pthread failed",
+               .suggestion = "Open an Issue with all relevant log files and restart FRR"
+       },
+       {
+               .code = EC_PATH_PCEP_PCC_INIT,
+               .title = "PCC initialization error",
+               .description = "pceplib PCC initialization call failed",
+               .suggestion = "Open an Issue with all relevant log files and restart FRR"
+       },
+       {
+               .code = EC_PATH_PCEP_PCC_FINI,
+               .title = "PCC finalization error",
+               .description = "pceplib PCC finalization call failed",
+               .suggestion = "Open an Issue with all relevant log files and restart FRR"
+       },
+       {
+               .code = EC_PATH_PCEP_PCC_CONF_UPDATE,
+               .title = "PCC configuration update error",
+               .description = "The update of the PCC configuration failed",
+               .suggestion = "Open an Issue with all relevant log files and restart FRR"
+       },
+       {
+               .code = END_FERR,
+       }
+};
+
+static struct log_ref ferr_path_warn[] = {
+       {
+               .code = EC_PATH_PCEP_LIB_CONNECT,
+               .title = "PCC connection error",
+               .description = "The PCEP module failed to connected to configured PCE",
+               .suggestion = "Check the connectivity between the PCC and the PCE"
+       },
+       {
+               .code = EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
+               .title = "PCC connection error",
+               .description = "The PCEP module did not try to connect because it is missing a source address",
+               .suggestion = "Wait for the router ID to be defined or set the PCC source address in the configuration"
+       },
+       {
+               .code = EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
+               .title = "Recoverable internal error",
+               .description = "Some recoverable internal error",
+               .suggestion = "Open an Issue with all relevant log files"
+       },
+       {
+               .code = EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE,
+               .title = "Unsupported PCEP feature",
+               .description = "Receved an unsupported PCEP message",
+               .suggestion = "The PCC and PCE are probably not compatible. Open an Issue with all relevant log files"
+       },
+       {
+               .code = EC_PATH_PCEP_UNEXPECTED_PCEP_MESSAGE,
+               .title = "Unexpected PCEP message",
+               .description = "The PCEP module received an unexpected PCEP message",
+               .suggestion = "Open an Issue with all relevant log files"
+       },
+       {
+               .code = EC_PATH_PCEP_UNEXPECTED_PCEPLIB_EVENT,
+               .title = "Unexpected pceplib event",
+               .description = "The PCEP module received an unexpected event from pceplib",
+               .suggestion = "Open an Issue with all relevant log files"
+       },
+       {
+               .code = EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT,
+               .title = "Unexpected PCEP object",
+               .description = "The PCEP module received an unexpected PCEP object from a PCE",
+               .suggestion = "Open an Issue with all relevant log files"
+       },
+       {
+               .code = EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
+               .title = "Unexpected PCEP TLV",
+               .description = "The PCEP module received an unexpected PCEP TLV from a PCE",
+               .suggestion = "Open an Issue with all relevant log files"
+       },
+       {
+               .code = EC_PATH_PCEP_UNEXPECTED_PCEP_ERO_SUBOBJ,
+               .title = "Unexpected PCEP ERO sub-object",
+               .description = "The PCEP module received an unexpected PCEP ERO sub-object from a PCE",
+               .suggestion = "Open an Issue with all relevant log files"
+       },
+       {
+               .code = EC_PATH_PCEP_UNEXPECTED_SR_NAI,
+               .title = "Unexpected PCEP SR segment NAI",
+               .description = "The PCEP module received an SR segment with an unsupported NAI specification from the PCE",
+               .suggestion = "Open an Issue with all relevant log files"
+       },
+       {
+               .code = EC_PATH_PCEP_COMPUTATION_REQUEST_TIMEOUT,
+               .title = "Computation request timeout",
+               .description = "The PCE did not respond in time to the PCC computation request",
+               .suggestion = "The PCE is overloaded or incompatible with the PCC, try with a different PCE"
+       },
+       {
+               .code = END_FERR,
+       }
+
+};
+/* clang-format on */
+
+void path_error_init(void)
+{
+       log_ref_add(ferr_path_err);
+       log_ref_add(ferr_path_warn);
+}
diff --git a/pathd/path_errors.h b/pathd/path_errors.h
new file mode 100644 (file)
index 0000000..72e127f
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#ifndef __PATH_ERRORS_H__
+#define __PATH_ERRORS_H__
+
+#include "lib/ferr.h"
+
+enum path_log_refs {
+       EC_PATH_PCEP_INIT = PATH_FERR_START,
+       EC_PATH_SYSTEM_CALL,
+       EC_PATH_PCEP_PCC_INIT,
+       EC_PATH_PCEP_PCC_FINI,
+       EC_PATH_PCEP_PCC_CONF_UPDATE,
+       EC_PATH_PCEP_LIB_CONNECT,
+       EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
+       EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
+       EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE,
+       EC_PATH_PCEP_UNEXPECTED_PCEP_MESSAGE,
+       EC_PATH_PCEP_UNEXPECTED_PCEPLIB_EVENT,
+       EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT,
+       EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
+       EC_PATH_PCEP_UNEXPECTED_PCEP_ERO_SUBOBJ,
+       EC_PATH_PCEP_UNEXPECTED_SR_NAI,
+       EC_PATH_PCEP_COMPUTATION_REQUEST_TIMEOUT
+};
+
+extern void path_error_init(void);
+
+#endif
diff --git a/pathd/path_main.c b/pathd/path_main.c
new file mode 100644 (file)
index 0000000..8b7d4ab
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2020  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
+ */
+#include <zebra.h>
+
+#include <lib/version.h>
+#include "getopt.h"
+#include "thread.h"
+#include "command.h"
+#include "log.h"
+#include "memory.h"
+#include "privs.h"
+#include "sigevent.h"
+#include "libfrr.h"
+#include "vrf.h"
+#include "filter.h"
+
+#include "pathd.h"
+#include "path_nb.h"
+#include "path_zebra.h"
+#include "path_errors.h"
+
+char backup_config_file[256];
+
+zebra_capabilities_t _caps_p[] = {};
+
+struct zebra_privs_t pathd_privs = {
+#if defined(FRR_USER) && defined(FRR_GROUP)
+       .user = FRR_USER,
+       .group = FRR_GROUP,
+#endif
+#if defined(VTY_GROUP)
+       .vty_group = VTY_GROUP,
+#endif
+       .caps_p = _caps_p,
+       .cap_num_p = array_size(_caps_p),
+       .cap_num_i = 0};
+
+struct option longopts[] = {{0}};
+
+/* Master of threads. */
+struct thread_master *master;
+
+static struct frr_daemon_info pathd_di;
+
+/* SIGHUP handler. */
+static void sighup(void)
+{
+       zlog_info("SIGHUP received");
+
+       /* Reload config file. */
+       vty_read_config(NULL, pathd_di.config_file, config_default);
+}
+
+/* SIGINT / SIGTERM handler. */
+static void sigint(void)
+{
+       zlog_notice("Terminating on signal");
+
+       exit(0);
+}
+
+/* SIGUSR1 handler. */
+static void sigusr1(void)
+{
+       zlog_rotate();
+}
+
+struct quagga_signal_t path_signals[] = {
+       {
+               .signal = SIGHUP,
+               .handler = &sighup,
+       },
+       {
+               .signal = SIGUSR1,
+               .handler = &sigusr1,
+       },
+       {
+               .signal = SIGINT,
+               .handler = &sigint,
+       },
+       {
+               .signal = SIGTERM,
+               .handler = &sigint,
+       },
+};
+
+static const struct frr_yang_module_info *pathd_yang_modules[] = {
+       &frr_filter_info,
+       &frr_interface_info,
+       &frr_pathd_info,
+};
+
+#define PATH_VTY_PORT 2621
+
+FRR_DAEMON_INFO(pathd, PATH, .vty_port = PATH_VTY_PORT,
+
+               .proghelp = "Implementation of PATH.",
+
+               .signals = path_signals, .n_signals = array_size(path_signals),
+
+               .privs = &pathd_privs, .yang_modules = pathd_yang_modules,
+               .n_yang_modules = array_size(pathd_yang_modules), )
+
+int main(int argc, char **argv, char **envp)
+{
+       frr_preinit(&pathd_di, argc, argv);
+       frr_opt_add("", longopts, "");
+
+       while (1) {
+               int opt;
+
+               opt = frr_getopt(argc, argv, NULL);
+
+               if (opt == EOF)
+                       break;
+
+               switch (opt) {
+               case 0:
+                       break;
+               default:
+                       frr_help_exit(1);
+                       break;
+               }
+       }
+
+       master = frr_init();
+
+       access_list_init();
+
+       path_error_init();
+       path_zebra_init(master);
+       path_cli_init();
+
+       frr_config_fork();
+       frr_run(master);
+
+       /* Not reached. */
+       return 0;
+}
diff --git a/pathd/path_memory.c b/pathd/path_memory.c
new file mode 100644 (file)
index 0000000..ad4904a
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#include <zebra.h>
+
+#include <memory.h>
+
+#include "pathd/path_memory.h"
+
+DEFINE_MGROUP(PATHD, "pathd")
diff --git a/pathd/path_memory.h b/pathd/path_memory.h
new file mode 100644 (file)
index 0000000..e2f6787
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#ifndef _FRR_PATH_MEMORY_H_
+#define _FRR_PATH_MEMORY_H_
+
+#include "memory.h"
+
+DECLARE_MGROUP(PATHD)
+
+#endif /* _FRR_PATH_MEMORY_H_ */
diff --git a/pathd/path_nb.c b/pathd/path_nb.c
new file mode 100644 (file)
index 0000000..a210e31
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#include <zebra.h>
+
+#include "northbound.h"
+#include "libfrr.h"
+
+#include "pathd/path_nb.h"
+
+static int iter_objfun_cb(const struct lyd_node *dnode, void *arg);
+static int dummy_create(struct nb_cb_create_args *args);
+static int dummy_modify(struct nb_cb_modify_args *args);
+static int dummy_destroy(struct nb_cb_destroy_args *args);
+
+struct of_cb_pref {
+       uint32_t index;
+       enum objfun_type type;
+       struct of_cb_pref *next;
+};
+
+struct of_cb_args {
+       struct of_cb_pref *first;
+       uint32_t free_slot;
+       struct of_cb_pref prefs[MAX_OBJFUN_TYPE];
+};
+
+/* clang-format off */
+const struct frr_yang_module_info frr_pathd_info = {
+       .name = "frr-pathd",
+       .nodes = {
+               {
+                       .xpath = "/frr-pathd:pathd",
+                       .cbs = {
+                               .apply_finish = pathd_apply_finish,
+                       },
+                       .priority = NB_DFLT_PRIORITY + 1
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/segment-list",
+                       .cbs = {
+                               .create = pathd_srte_segment_list_create,
+                               .cli_show = cli_show_srte_segment_list,
+                               .destroy = pathd_srte_segment_list_destroy,
+                               .get_next = pathd_srte_segment_list_get_next,
+                               .get_keys = pathd_srte_segment_list_get_keys,
+                               .lookup_entry = pathd_srte_segment_list_lookup_entry,
+                       },
+                       .priority = NB_DFLT_PRIORITY - 1
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/segment-list/protocol-origin",
+                       .cbs = {
+                               .modify = pathd_srte_segment_list_protocol_origin_modify,
+                       },
+                       .priority = NB_DFLT_PRIORITY - 1
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/segment-list/originator",
+                       .cbs = {
+                               .modify = pathd_srte_segment_list_originator_modify,
+                       },
+                       .priority = NB_DFLT_PRIORITY - 1
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/segment-list/segment",
+                       .cbs = {
+                               .create = pathd_srte_segment_list_segment_create,
+                               .cli_show = cli_show_srte_segment_list_segment,
+                               .destroy = pathd_srte_segment_list_segment_destroy,
+                       },
+                       .priority = NB_DFLT_PRIORITY - 1
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/segment-list/segment/sid-value",
+                       .cbs = {
+                               .modify = pathd_srte_segment_list_segment_sid_value_modify,
+                       },
+                       .priority = NB_DFLT_PRIORITY - 1
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai",
+                       .cbs = {
+                               .create = dummy_create,
+                               .destroy = pathd_srte_segment_list_segment_nai_destroy,
+                               .apply_finish = pathd_srte_segment_list_segment_nai_apply_finish
+                       },
+                       .priority = NB_DFLT_PRIORITY - 1
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/type",
+                       .cbs = {.modify = dummy_modify}
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/local-address",
+                       .cbs = {.modify = dummy_modify}
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/local-interface",
+                       .cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/remote-address",
+                       .cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/remote-interface",
+                       .cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy",
+                       .cbs = {
+                               .create = pathd_srte_policy_create,
+                               .cli_show = cli_show_srte_policy,
+                               .destroy = pathd_srte_policy_destroy,
+                               .get_next = pathd_srte_policy_get_next,
+                               .get_keys = pathd_srte_policy_get_keys,
+                               .lookup_entry = pathd_srte_policy_lookup_entry,
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/name",
+                       .cbs = {
+                               .modify = pathd_srte_policy_name_modify,
+                               .cli_show = cli_show_srte_policy_name,
+                               .destroy = pathd_srte_policy_name_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/binding-sid",
+                       .cbs = {
+                               .modify = pathd_srte_policy_binding_sid_modify,
+                               .cli_show = cli_show_srte_policy_binding_sid,
+                               .destroy = pathd_srte_policy_binding_sid_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/is-operational",
+                       .cbs = {
+                               .get_elem = pathd_srte_policy_is_operational_get_elem
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path",
+                       .cbs = {
+                               .create = pathd_srte_policy_candidate_path_create,
+                               .cli_show = cli_show_srte_policy_candidate_path,
+                               .destroy = pathd_srte_policy_candidate_path_destroy,
+                               .get_next = pathd_srte_policy_candidate_path_get_next,
+                               .get_keys = pathd_srte_policy_candidate_path_get_keys,
+                               .lookup_entry = pathd_srte_policy_candidate_path_lookup_entry,
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/name",
+                       .cbs = {
+                               .modify = pathd_srte_policy_candidate_path_name_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/is-best-candidate-path",
+                       .cbs = {
+                               .get_elem = pathd_srte_policy_candidate_path_is_best_candidate_path_get_elem,
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/protocol-origin",
+                       .cbs = {
+                               .modify = pathd_srte_policy_candidate_path_protocol_origin_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/originator",
+                       .cbs = {
+                               .modify = pathd_srte_policy_candidate_path_originator_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/discriminator",
+                       .cbs = {
+                               .get_elem = pathd_srte_policy_candidate_path_discriminator_get_elem,
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/type",
+                       .cbs = {
+                               .modify = pathd_srte_policy_candidate_path_type_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/segment-list-name",
+                       .cbs = {
+                               .destroy = pathd_srte_policy_candidate_path_segment_list_name_destroy,
+                               .modify = pathd_srte_policy_candidate_path_segment_list_name_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/bandwidth",
+                       .cbs = {
+                               .create = dummy_create,
+                               .destroy = pathd_srte_policy_candidate_path_bandwidth_destroy,
+                               .apply_finish = pathd_srte_policy_candidate_path_bandwidth_apply_finish
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/bandwidth/required",
+                       .cbs = {.modify = dummy_modify}
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/bandwidth/value",
+                       .cbs = {.modify = dummy_modify}
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/exclude-any",
+                       .cbs = {
+                               .modify = pathd_srte_policy_candidate_path_exclude_any_modify,
+                               .destroy = pathd_srte_policy_candidate_path_exclude_any_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/include-any",
+                       .cbs = {
+                               .modify = pathd_srte_policy_candidate_path_include_any_modify,
+                               .destroy = pathd_srte_policy_candidate_path_include_any_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/include-all",
+                       .cbs = {
+                               .modify = pathd_srte_policy_candidate_path_include_all_modify,
+                               .destroy = pathd_srte_policy_candidate_path_include_all_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics",
+                       .cbs = {
+                               .create = dummy_create,
+                               .destroy = pathd_srte_policy_candidate_path_metrics_destroy,
+                               .apply_finish = pathd_srte_policy_candidate_path_metrics_apply_finish
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics/value",
+                       .cbs = {.modify = dummy_modify}
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics/required",
+                       .cbs = {.modify = dummy_modify}
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics/is-bound",
+                       .cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics/is-computed",
+                       .cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/objective-function",
+                       .cbs = {
+                               .create = dummy_create,
+                               .destroy = pathd_srte_policy_candidate_path_objfun_destroy,
+                               .apply_finish = pathd_srte_policy_candidate_path_objfun_apply_finish
+                       }
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/objective-function/required",
+                       .cbs = {.modify = dummy_modify}
+               },
+               {
+                       .xpath = "/frr-pathd:pathd/srte/policy/candidate-path/constraints/objective-function/type",
+                       .cbs = {.modify = dummy_modify}
+               },
+               {
+                       .xpath = NULL,
+               },
+       }
+};
+
+void iter_objfun_prefs(const struct lyd_node *dnode, const char* path,
+                      of_pref_cp_t fun, void *arg)
+{
+       struct of_cb_args args = {0};
+       struct of_cb_pref *p;
+
+       yang_dnode_iterate(iter_objfun_cb, &args, dnode, path);
+       for (p = args.first; p != NULL; p = p->next)
+               fun(p->type, arg);
+}
+
+int iter_objfun_cb(const struct lyd_node *dnode, void *arg)
+{
+       struct of_cb_args *of_arg = arg;
+       struct of_cb_pref *pref;
+       struct of_cb_pref **p;
+
+       if (of_arg->free_slot >= MAX_OBJFUN_TYPE)
+               return YANG_ITER_STOP;
+
+       pref = &of_arg->prefs[of_arg->free_slot++];
+
+       pref->index = yang_dnode_get_uint32(dnode, "./index");
+       pref->type = yang_dnode_get_enum(dnode, "./type");
+
+       /* Simplistic insertion sort */
+       p = &of_arg->first;
+       while (true) {
+               if (*p == NULL) {
+                       *p = pref;
+                       break;
+               }
+               if ((*p)->index >= pref->index) {
+                       pref->next = *p;
+                       *p = pref;
+                       break;
+               }
+               p = &(*p)->next;
+       }
+
+       return YANG_ITER_CONTINUE;
+}
+
+int dummy_create(struct nb_cb_create_args *args)
+{
+       return NB_OK;
+}
+
+int dummy_modify(struct nb_cb_modify_args *args)
+{
+       return NB_OK;
+}
+
+int dummy_destroy(struct nb_cb_destroy_args *args)
+{
+       return NB_OK;
+}
diff --git a/pathd/path_nb.h b/pathd/path_nb.h
new file mode 100644 (file)
index 0000000..3a0b386
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#ifndef _FRR_PATH_NB_H_
+#define _FRR_PATH_NB_H_
+
+#include "pathd/pathd.h"
+
+extern const struct frr_yang_module_info frr_pathd_info;
+
+/* Mandatory callbacks. */
+int pathd_srte_segment_list_create(struct nb_cb_create_args *args);
+int pathd_srte_segment_list_destroy(struct nb_cb_destroy_args *args);
+
+const void *pathd_srte_segment_list_get_next(struct nb_cb_get_next_args *args);
+int pathd_srte_segment_list_get_keys(struct nb_cb_get_keys_args *args);
+const void *
+pathd_srte_segment_list_lookup_entry(struct nb_cb_lookup_entry_args *args);
+
+int pathd_srte_segment_list_segment_create(struct nb_cb_create_args *args);
+int pathd_srte_segment_list_segment_destroy(struct nb_cb_destroy_args *args);
+int pathd_srte_segment_list_protocol_origin_modify(
+       struct nb_cb_modify_args *args);
+int pathd_srte_segment_list_originator_modify(struct nb_cb_modify_args *args);
+int pathd_srte_segment_list_segment_sid_value_modify(
+       struct nb_cb_modify_args *args);
+int pathd_srte_segment_list_segment_nai_destroy(
+       struct nb_cb_destroy_args *args);
+void pathd_srte_segment_list_segment_nai_apply_finish(
+       struct nb_cb_apply_finish_args *args);
+int pathd_srte_policy_create(struct nb_cb_create_args *args);
+int pathd_srte_policy_destroy(struct nb_cb_destroy_args *args);
+const void *pathd_srte_policy_get_next(struct nb_cb_get_next_args *args);
+int pathd_srte_policy_get_keys(struct nb_cb_get_keys_args *args);
+const void *
+pathd_srte_policy_lookup_entry(struct nb_cb_lookup_entry_args *args);
+int pathd_srte_policy_name_modify(struct nb_cb_modify_args *args);
+int pathd_srte_policy_name_destroy(struct nb_cb_destroy_args *args);
+int pathd_srte_policy_binding_sid_modify(struct nb_cb_modify_args *args);
+int pathd_srte_policy_binding_sid_destroy(struct nb_cb_destroy_args *args);
+struct yang_data *
+pathd_srte_policy_is_operational_get_elem(struct nb_cb_get_elem_args *args);
+int pathd_srte_policy_candidate_path_create(struct nb_cb_create_args *args);
+int pathd_srte_policy_candidate_path_destroy(struct nb_cb_destroy_args *args);
+int pathd_srte_policy_candidate_path_name_modify(
+       struct nb_cb_modify_args *args);
+const void *
+pathd_srte_policy_candidate_path_get_next(struct nb_cb_get_next_args *args);
+int pathd_srte_policy_candidate_path_get_keys(struct nb_cb_get_keys_args *args);
+const void *pathd_srte_policy_candidate_path_lookup_entry(
+       struct nb_cb_lookup_entry_args *args);
+void pathd_srte_policy_candidate_path_bandwidth_apply_finish(
+       struct nb_cb_apply_finish_args *args);
+int pathd_srte_policy_candidate_path_bandwidth_destroy(
+       struct nb_cb_destroy_args *args);
+int pathd_srte_policy_candidate_path_exclude_any_modify(
+       struct nb_cb_modify_args *args);
+int pathd_srte_policy_candidate_path_exclude_any_destroy(
+       struct nb_cb_destroy_args *args);
+int pathd_srte_policy_candidate_path_include_any_modify(
+       struct nb_cb_modify_args *args);
+int pathd_srte_policy_candidate_path_include_any_destroy(
+       struct nb_cb_destroy_args *args);
+int pathd_srte_policy_candidate_path_include_all_modify(
+       struct nb_cb_modify_args *args);
+int pathd_srte_policy_candidate_path_include_all_destroy(
+       struct nb_cb_destroy_args *args);
+int pathd_srte_policy_candidate_path_metrics_destroy(
+       struct nb_cb_destroy_args *args);
+void pathd_srte_policy_candidate_path_metrics_apply_finish(
+       struct nb_cb_apply_finish_args *args);
+int pathd_srte_policy_candidate_path_objfun_destroy(
+       struct nb_cb_destroy_args *args);
+void pathd_srte_policy_candidate_path_objfun_apply_finish(
+       struct nb_cb_apply_finish_args *args);
+struct yang_data *
+pathd_srte_policy_candidate_path_is_best_candidate_path_get_elem(
+       struct nb_cb_get_elem_args *args);
+int pathd_srte_policy_candidate_path_protocol_origin_modify(
+       struct nb_cb_modify_args *args);
+int pathd_srte_policy_candidate_path_originator_modify(
+       struct nb_cb_modify_args *args);
+struct yang_data *pathd_srte_policy_candidate_path_discriminator_get_elem(
+       struct nb_cb_get_elem_args *args);
+int pathd_srte_policy_candidate_path_type_modify(
+       struct nb_cb_modify_args *args);
+int pathd_srte_policy_candidate_path_segment_list_name_modify(
+       struct nb_cb_modify_args *args);
+int pathd_srte_policy_candidate_path_segment_list_name_destroy(
+       struct nb_cb_destroy_args *args);
+
+/* Optional 'apply_finish' callbacks. */
+void pathd_apply_finish(struct nb_cb_apply_finish_args *args);
+
+/* Optional 'cli_show' callbacks. */
+void cli_show_srte_segment_list(struct vty *vty, struct lyd_node *dnode,
+                               bool show_defaults);
+void cli_show_srte_segment_list_segment(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults);
+void cli_show_srte_policy(struct vty *vty, struct lyd_node *dnode,
+                         bool show_defaults);
+void cli_show_srte_policy_name(struct vty *vty, struct lyd_node *dnode,
+                              bool show_defaults);
+void cli_show_srte_policy_binding_sid(struct vty *vty, struct lyd_node *dnode,
+                                     bool show_defaults);
+void cli_show_srte_policy_candidate_path(struct vty *vty,
+                                        struct lyd_node *dnode,
+                                        bool show_defaults);
+
+/* Utility functions */
+typedef void (*of_pref_cp_t)(enum objfun_type type, void *arg);
+void iter_objfun_prefs(const struct lyd_node *dnode, const char *path,
+                      of_pref_cp_t fun, void *arg);
+
+#endif /* _FRR_PATH_NB_H_ */
diff --git a/pathd/path_nb_config.c b/pathd/path_nb_config.c
new file mode 100644 (file)
index 0000000..669db16
--- /dev/null
@@ -0,0 +1,731 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#include <zebra.h>
+#include <lib_errors.h>
+
+#include "northbound.h"
+#include "libfrr.h"
+
+#include "pathd/path_zebra.h"
+#include "pathd/path_nb.h"
+
+/*
+ * XPath: /frr-pathd:pathd
+ */
+void pathd_apply_finish(struct nb_cb_apply_finish_args *args)
+{
+       srte_apply_changes();
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/segment-list
+ */
+int pathd_srte_segment_list_create(struct nb_cb_create_args *args)
+{
+       struct srte_segment_list *segment_list;
+       const char *name;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       name = yang_dnode_get_string(args->dnode, "./name");
+       segment_list = srte_segment_list_add(name);
+       nb_running_set_entry(args->dnode, segment_list);
+       SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
+
+       return NB_OK;
+}
+
+int pathd_srte_segment_list_destroy(struct nb_cb_destroy_args *args)
+{
+       struct srte_segment_list *segment_list;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       segment_list = nb_running_unset_entry(args->dnode);
+       SET_FLAG(segment_list->flags, F_SEGMENT_LIST_DELETED);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/segment-list/protocol-origin
+ */
+int pathd_srte_segment_list_protocol_origin_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct srte_segment_list *segment_list;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       segment_list = nb_running_get_entry(args->dnode, NULL, true);
+       segment_list->protocol_origin = yang_dnode_get_enum(args->dnode, NULL);
+       SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/segment-list/originator
+ */
+int pathd_srte_segment_list_originator_modify(struct nb_cb_modify_args *args)
+{
+       struct srte_segment_list *segment_list;
+       const char *originator;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       segment_list = nb_running_get_entry(args->dnode, NULL, true);
+       originator = yang_dnode_get_string(args->dnode, NULL);
+       strlcpy(segment_list->originator, originator,
+               sizeof(segment_list->originator));
+       SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
+
+       return NB_OK;
+}
+
+
+/*
+ * XPath: /frr-pathd:pathd/srte/segment-list/segment
+ */
+int pathd_srte_segment_list_segment_create(struct nb_cb_create_args *args)
+{
+       struct srte_segment_list *segment_list;
+       struct srte_segment_entry *segment;
+       uint32_t index;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       segment_list = nb_running_get_entry(args->dnode, NULL, true);
+       index = yang_dnode_get_uint32(args->dnode, "./index");
+       segment = srte_segment_entry_add(segment_list, index);
+       nb_running_set_entry(args->dnode, segment);
+       SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
+
+       return NB_OK;
+}
+
+int pathd_srte_segment_list_segment_destroy(struct nb_cb_destroy_args *args)
+{
+       struct srte_segment_entry *segment;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       segment = nb_running_unset_entry(args->dnode);
+       SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED);
+
+       srte_segment_entry_del(segment);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/segment-list/segment/sid-value
+ */
+int pathd_srte_segment_list_segment_sid_value_modify(
+       struct nb_cb_modify_args *args)
+{
+       mpls_label_t sid_value;
+       struct srte_segment_entry *segment;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       segment = nb_running_get_entry(args->dnode, NULL, true);
+       sid_value = yang_dnode_get_uint32(args->dnode, NULL);
+       segment->sid_value = sid_value;
+       SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED);
+
+       return NB_OK;
+}
+
+int pathd_srte_segment_list_segment_nai_destroy(struct nb_cb_destroy_args *args)
+{
+       struct srte_segment_entry *segment;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       segment = nb_running_get_entry(args->dnode, NULL, true);
+       segment->nai_type = SRTE_SEGMENT_NAI_TYPE_NONE;
+       segment->nai_local_addr.ipa_type = IPADDR_NONE;
+       segment->nai_local_iface = 0;
+       segment->nai_remote_addr.ipa_type = IPADDR_NONE;
+       segment->nai_remote_iface = 0;
+
+       return NB_OK;
+}
+
+void pathd_srte_segment_list_segment_nai_apply_finish(
+       struct nb_cb_apply_finish_args *args)
+{
+       struct srte_segment_entry *segment;
+       enum srte_segment_nai_type type;
+       struct ipaddr local_addr, remote_addr;
+       uint32_t local_iface = 0, remote_iface = 0;
+
+       segment = nb_running_get_entry(args->dnode, NULL, true);
+       type = yang_dnode_get_enum(args->dnode, "./type");
+
+       yang_dnode_get_ip(&local_addr, args->dnode, "./local-address");
+
+       switch (type) {
+       case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
+       case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
+               break;
+       case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
+       case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
+               yang_dnode_get_ip(&remote_addr, args->dnode,
+                                 "./remote-address");
+               break;
+       case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
+               yang_dnode_get_ip(&remote_addr, args->dnode,
+                                 "./remote-address");
+               local_iface =
+                       yang_dnode_get_uint32(args->dnode, "./local-interface");
+               remote_iface = yang_dnode_get_uint32(args->dnode,
+                                                    "./remote-interface");
+               break;
+       default:
+               break;
+       }
+
+       srte_segment_entry_set_nai(segment, type, &local_addr, local_iface,
+                                  &remote_addr, remote_iface);
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy
+ */
+int pathd_srte_policy_create(struct nb_cb_create_args *args)
+{
+       struct srte_policy *policy;
+       uint32_t color;
+       struct ipaddr endpoint;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       color = yang_dnode_get_uint32(args->dnode, "./color");
+       yang_dnode_get_ip(&endpoint, args->dnode, "./endpoint");
+       policy = srte_policy_add(color, &endpoint);
+
+       nb_running_set_entry(args->dnode, policy);
+       SET_FLAG(policy->flags, F_POLICY_NEW);
+
+       return NB_OK;
+}
+
+int pathd_srte_policy_destroy(struct nb_cb_destroy_args *args)
+{
+       struct srte_policy *policy;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       policy = nb_running_unset_entry(args->dnode);
+       SET_FLAG(policy->flags, F_POLICY_DELETED);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/name
+ */
+int pathd_srte_policy_name_modify(struct nb_cb_modify_args *args)
+{
+       struct srte_policy *policy;
+       const char *name;
+
+       if (args->event != NB_EV_APPLY && args->event != NB_EV_VALIDATE)
+               return NB_OK;
+
+       policy = nb_running_get_entry(args->dnode, NULL, true);
+
+       if (args->event == NB_EV_VALIDATE) {
+               /* the policy name is fixed after setting it once */
+               if (strlen(policy->name) > 0) {
+                       flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
+                                 "The SR Policy name is fixed!");
+                       return NB_ERR_RESOURCE;
+               } else
+                       return NB_OK;
+       }
+
+       name = yang_dnode_get_string(args->dnode, NULL);
+       strlcpy(policy->name, name, sizeof(policy->name));
+       SET_FLAG(policy->flags, F_POLICY_MODIFIED);
+
+       return NB_OK;
+}
+
+int pathd_srte_policy_name_destroy(struct nb_cb_destroy_args *args)
+{
+       struct srte_policy *policy;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       policy = nb_running_get_entry(args->dnode, NULL, true);
+       policy->name[0] = '\0';
+       SET_FLAG(policy->flags, F_POLICY_MODIFIED);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/binding-sid
+ */
+int pathd_srte_policy_binding_sid_modify(struct nb_cb_modify_args *args)
+{
+       struct srte_policy *policy;
+       mpls_label_t binding_sid;
+
+       policy = nb_running_get_entry(args->dnode, NULL, true);
+       binding_sid = yang_dnode_get_uint32(args->dnode, NULL);
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               break;
+       case NB_EV_PREPARE:
+               if (path_zebra_request_label(binding_sid) < 0)
+                       return NB_ERR_RESOURCE;
+               break;
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               srte_policy_update_binding_sid(policy, binding_sid);
+               SET_FLAG(policy->flags, F_POLICY_MODIFIED);
+               break;
+       }
+
+       return NB_OK;
+}
+
+int pathd_srte_policy_binding_sid_destroy(struct nb_cb_destroy_args *args)
+{
+       struct srte_policy *policy;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       policy = nb_running_get_entry(args->dnode, NULL, true);
+       srte_policy_update_binding_sid(policy, MPLS_LABEL_NONE);
+       SET_FLAG(policy->flags, F_POLICY_MODIFIED);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/candidate-path
+ */
+int pathd_srte_policy_candidate_path_create(struct nb_cb_create_args *args)
+{
+       struct srte_policy *policy;
+       struct srte_candidate *candidate;
+       uint32_t preference;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       policy = nb_running_get_entry(args->dnode, NULL, true);
+       preference = yang_dnode_get_uint32(args->dnode, "./preference");
+       candidate = srte_candidate_add(policy, preference);
+       nb_running_set_entry(args->dnode, candidate);
+       SET_FLAG(candidate->flags, F_CANDIDATE_NEW);
+
+       return NB_OK;
+}
+
+int pathd_srte_policy_candidate_path_destroy(struct nb_cb_destroy_args *args)
+{
+       struct srte_candidate *candidate;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       candidate = nb_running_unset_entry(args->dnode);
+       SET_FLAG(candidate->flags, F_CANDIDATE_DELETED);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/candidate-path/name
+ */
+int pathd_srte_policy_candidate_path_name_modify(struct nb_cb_modify_args *args)
+{
+       struct srte_candidate *candidate;
+       const char *name;
+       char xpath[XPATH_MAXLEN];
+       char xpath_buf[XPATH_MAXLEN - 3];
+
+       if (args->event != NB_EV_APPLY && args->event != NB_EV_VALIDATE)
+               return NB_OK;
+
+       /* the candidate name is fixed after setting it once, this is checked
+        * here */
+       if (args->event == NB_EV_VALIDATE) {
+               /* first get the precise path to the candidate path */
+               yang_dnode_get_path(args->dnode, xpath_buf, sizeof(xpath_buf));
+               snprintf(xpath, sizeof(xpath), "%s%s", xpath_buf, "/..");
+
+               candidate = nb_running_get_entry_non_rec(NULL, xpath, false);
+
+               /* then check if it exists and if the name was provided */
+               if (candidate && strlen(candidate->name) > 0) {
+                       flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
+                                 "The candidate name is fixed!");
+                       return NB_ERR_RESOURCE;
+               } else
+                       return NB_OK;
+       }
+
+       candidate = nb_running_get_entry(args->dnode, NULL, true);
+
+       name = yang_dnode_get_string(args->dnode, NULL);
+       strlcpy(candidate->name, name, sizeof(candidate->name));
+       SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
+
+       return NB_OK;
+}
+
+
+static int affinity_filter_modify(struct nb_cb_modify_args *args,
+                                 enum affinity_filter_type type)
+{
+       uint32_t filter;
+       struct srte_candidate *candidate;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       assert(args->context != NULL);
+       candidate = nb_running_get_entry(args->dnode, NULL, true);
+       filter = yang_dnode_get_uint32(args->dnode, NULL);
+       srte_candidate_set_affinity_filter(candidate, type, filter);
+
+       return NB_OK;
+}
+
+static int affinity_filter_destroy(struct nb_cb_destroy_args *args,
+                                  enum affinity_filter_type type)
+{
+       struct srte_candidate *candidate;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       assert(args->context != NULL);
+       candidate = nb_running_get_entry(args->dnode, NULL, true);
+       srte_candidate_unset_affinity_filter(candidate, type);
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/exclude-any
+ */
+
+int pathd_srte_policy_candidate_path_exclude_any_modify(
+       struct nb_cb_modify_args *args)
+{
+       return affinity_filter_modify(args, AFFINITY_FILTER_EXCLUDE_ANY);
+}
+
+int pathd_srte_policy_candidate_path_exclude_any_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       return affinity_filter_destroy(args, AFFINITY_FILTER_EXCLUDE_ANY);
+}
+
+
+/*
+ * XPath:
+ * /frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/include-any
+ */
+int pathd_srte_policy_candidate_path_include_any_modify(
+       struct nb_cb_modify_args *args)
+{
+       return affinity_filter_modify(args, AFFINITY_FILTER_INCLUDE_ANY);
+}
+
+int pathd_srte_policy_candidate_path_include_any_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       return affinity_filter_destroy(args, AFFINITY_FILTER_INCLUDE_ANY);
+}
+
+
+/*
+ * XPath:
+ * /frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/include-all
+ */
+int pathd_srte_policy_candidate_path_include_all_modify(
+       struct nb_cb_modify_args *args)
+{
+       return affinity_filter_modify(args, AFFINITY_FILTER_INCLUDE_ALL);
+}
+
+int pathd_srte_policy_candidate_path_include_all_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       return affinity_filter_destroy(args, AFFINITY_FILTER_INCLUDE_ALL);
+}
+
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics
+ */
+int pathd_srte_policy_candidate_path_metrics_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct srte_candidate *candidate;
+       enum srte_candidate_metric_type type;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       assert(args->context != NULL);
+       candidate = nb_running_get_entry(args->dnode, NULL, true);
+
+       type = yang_dnode_get_enum(args->dnode, "./type");
+       srte_candidate_unset_metric(candidate, type);
+
+       return NB_OK;
+}
+
+void pathd_srte_policy_candidate_path_metrics_apply_finish(
+       struct nb_cb_apply_finish_args *args)
+{
+       struct srte_candidate *candidate;
+       enum srte_candidate_metric_type type;
+       float value;
+       bool required, is_bound = false, is_computed = false;
+
+       assert(args->context != NULL);
+
+       candidate = nb_running_get_entry(args->dnode, NULL, true);
+
+       type = yang_dnode_get_enum(args->dnode, "./type");
+       value = (float)yang_dnode_get_dec64(args->dnode, "./value");
+       required = yang_dnode_get_bool(args->dnode, "./required");
+       if (yang_dnode_exists(args->dnode, "./is-bound"))
+               is_bound = yang_dnode_get_bool(args->dnode, "./is-bound");
+       if (yang_dnode_exists(args->dnode, "./is-computed"))
+               is_computed = yang_dnode_get_bool(args->dnode, "./is-computed");
+
+       srte_candidate_set_metric(candidate, type, value, required, is_bound,
+                                 is_computed);
+}
+
+/*
+ * XPath:
+ * /frr-pathd:pathd/srte/policy/candidate-path/constraints/objective-function
+ */
+int pathd_srte_policy_candidate_path_objfun_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct srte_candidate *candidate;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       assert(args->context != NULL);
+
+       candidate = nb_running_get_entry(args->dnode, NULL, true);
+       srte_candidate_unset_objfun(candidate);
+
+       return NB_OK;
+}
+
+void pathd_srte_policy_candidate_path_objfun_apply_finish(
+       struct nb_cb_apply_finish_args *args)
+{
+       struct srte_candidate *candidate;
+       enum objfun_type type;
+       bool required;
+
+       candidate = nb_running_get_entry(args->dnode, NULL, true);
+       required = yang_dnode_get_bool(args->dnode, "./required");
+       type = yang_dnode_get_enum(args->dnode, "./type");
+       srte_candidate_set_objfun(candidate, required, type);
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/candidate-path/protocol-origin
+ */
+int pathd_srte_policy_candidate_path_protocol_origin_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct srte_candidate *candidate;
+       enum srte_protocol_origin protocol_origin;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       candidate = nb_running_get_entry(args->dnode, NULL, true);
+       protocol_origin = yang_dnode_get_enum(args->dnode, NULL);
+       candidate->protocol_origin = protocol_origin;
+       candidate->lsp->protocol_origin = protocol_origin;
+       SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/candidate-path/originator
+ */
+int pathd_srte_policy_candidate_path_originator_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct srte_candidate *candidate;
+       const char *originator;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       candidate = nb_running_get_entry(args->dnode, NULL, true);
+       originator = yang_dnode_get_string(args->dnode, NULL);
+       strlcpy(candidate->originator, originator,
+               sizeof(candidate->originator));
+       strlcpy(candidate->lsp->originator, originator,
+               sizeof(candidate->lsp->originator));
+       SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/candidate-path/type
+ */
+int pathd_srte_policy_candidate_path_type_modify(struct nb_cb_modify_args *args)
+{
+       struct srte_candidate *candidate;
+       enum srte_candidate_type type;
+       char xpath[XPATH_MAXLEN];
+       char xpath_buf[XPATH_MAXLEN - 3];
+
+       if (args->event != NB_EV_APPLY && args->event != NB_EV_VALIDATE)
+               return NB_OK;
+
+       /* the candidate type is fixed after setting it once, this is checked
+        * here */
+       if (args->event == NB_EV_VALIDATE) {
+               /* first get the precise path to the candidate path */
+               yang_dnode_get_path(args->dnode, xpath_buf, sizeof(xpath_buf));
+               snprintf(xpath, sizeof(xpath), "%s%s", xpath_buf, "/..");
+
+               candidate = nb_running_get_entry_non_rec(NULL, xpath, false);
+
+               /* then check if it exists and if the type was provided */
+               if (candidate
+                   && candidate->type != SRTE_CANDIDATE_TYPE_UNDEFINED) {
+                       flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
+                                 "The candidate type is fixed!");
+                       return NB_ERR_RESOURCE;
+               } else
+                       return NB_OK;
+       }
+
+       candidate = nb_running_get_entry(args->dnode, NULL, true);
+
+       type = yang_dnode_get_enum(args->dnode, NULL);
+       candidate->type = type;
+       SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/candidate-path/segment-list-name
+ */
+int pathd_srte_policy_candidate_path_segment_list_name_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct srte_candidate *candidate;
+       const char *segment_list_name;
+
+       candidate = nb_running_get_entry(args->dnode, NULL, true);
+       segment_list_name = yang_dnode_get_string(args->dnode, NULL);
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       candidate->segment_list = srte_segment_list_find(segment_list_name);
+       candidate->lsp->segment_list = candidate->segment_list;
+       assert(candidate->segment_list);
+       SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
+
+       return NB_OK;
+}
+
+int pathd_srte_policy_candidate_path_segment_list_name_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct srte_candidate *candidate;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       candidate = nb_running_get_entry(args->dnode, NULL, true);
+       candidate->segment_list = NULL;
+       candidate->lsp->segment_list = NULL;
+       SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/candidate-path/constraints/bandwidth
+ */
+void pathd_srte_policy_candidate_path_bandwidth_apply_finish(
+       struct nb_cb_apply_finish_args *args)
+{
+       struct srte_candidate *candidate;
+       float value;
+       bool required;
+
+       assert(args->context != NULL);
+
+       candidate = nb_running_get_entry(args->dnode, NULL, true);
+       value = (float)yang_dnode_get_dec64(args->dnode, "./value");
+       required = yang_dnode_get_bool(args->dnode, "./required");
+       srte_candidate_set_bandwidth(candidate, value, required);
+}
+
+int pathd_srte_policy_candidate_path_bandwidth_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct srte_candidate *candidate;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       assert(args->context != NULL);
+       candidate = nb_running_get_entry(args->dnode, NULL, true);
+       srte_candidate_unset_bandwidth(candidate);
+       return NB_OK;
+}
diff --git a/pathd/path_nb_state.c b/pathd/path_nb_state.c
new file mode 100644 (file)
index 0000000..60f04f4
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "prefix.h"
+#include "table.h"
+#include "command.h"
+#include "northbound.h"
+#include "libfrr.h"
+
+#include "pathd/pathd.h"
+#include "pathd/path_nb.h"
+
+/*
+ * XPath: /frr-pathd:pathd/srte/segment-list
+ */
+const void *pathd_srte_segment_list_get_next(struct nb_cb_get_next_args *args)
+{
+       struct srte_segment_list *segment_list =
+               (struct srte_segment_list *)args->list_entry;
+
+       if (args->list_entry == NULL)
+               segment_list =
+                       RB_MIN(srte_segment_list_head, &srte_segment_lists);
+       else
+               segment_list = RB_NEXT(srte_segment_list_head, segment_list);
+
+       return segment_list;
+}
+
+int pathd_srte_segment_list_get_keys(struct nb_cb_get_keys_args *args)
+{
+       const struct srte_segment_list *segment_list =
+               (struct srte_segment_list *)args->list_entry;
+
+       args->keys->num = 1;
+       snprintf(args->keys->key[0], sizeof(args->keys->key[0]), "%s",
+                segment_list->name);
+
+       return NB_OK;
+}
+
+const void *
+pathd_srte_segment_list_lookup_entry(struct nb_cb_lookup_entry_args *args)
+{
+       return srte_segment_list_find(args->keys->key[0]);
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy
+ */
+const void *pathd_srte_policy_get_next(struct nb_cb_get_next_args *args)
+{
+       struct srte_policy *policy = (struct srte_policy *)args->list_entry;
+
+       if (args->list_entry == NULL)
+               policy = RB_MIN(srte_policy_head, &srte_policies);
+       else
+               policy = RB_NEXT(srte_policy_head, policy);
+
+       return policy;
+}
+
+int pathd_srte_policy_get_keys(struct nb_cb_get_keys_args *args)
+{
+       const struct srte_policy *policy =
+               (struct srte_policy *)args->list_entry;
+
+       args->keys->num = 2;
+       snprintf(args->keys->key[0], sizeof(args->keys->key[0]), "%u",
+                policy->color);
+       ipaddr2str(&policy->endpoint, args->keys->key[1],
+                  sizeof(args->keys->key[1]));
+
+       return NB_OK;
+}
+
+const void *pathd_srte_policy_lookup_entry(struct nb_cb_lookup_entry_args *args)
+{
+       uint32_t color;
+       struct ipaddr endpoint;
+
+       color = yang_str2uint32(args->keys->key[0]);
+       yang_str2ip(args->keys->key[1], &endpoint);
+
+       return srte_policy_find(color, &endpoint);
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/is-operational
+ */
+struct yang_data *
+pathd_srte_policy_is_operational_get_elem(struct nb_cb_get_elem_args *args)
+{
+       struct srte_policy *policy = (struct srte_policy *)args->list_entry;
+       bool is_operational = false;
+
+       if (policy->status == SRTE_POLICY_STATUS_UP)
+               is_operational = true;
+
+       return yang_data_new_bool(args->xpath, is_operational);
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/candidate-path
+ */
+const void *
+pathd_srte_policy_candidate_path_get_next(struct nb_cb_get_next_args *args)
+{
+       struct srte_policy *policy =
+               (struct srte_policy *)args->parent_list_entry;
+       struct srte_candidate *candidate =
+               (struct srte_candidate *)args->list_entry;
+
+       if (args->list_entry == NULL)
+               candidate =
+                       RB_MIN(srte_candidate_head, &policy->candidate_paths);
+       else
+               candidate = RB_NEXT(srte_candidate_head, candidate);
+
+       return candidate;
+}
+
+int pathd_srte_policy_candidate_path_get_keys(struct nb_cb_get_keys_args *args)
+{
+       const struct srte_candidate *candidate =
+               (struct srte_candidate *)args->list_entry;
+
+       args->keys->num = 1;
+       snprintf(args->keys->key[0], sizeof(args->keys->key[0]), "%u",
+                candidate->preference);
+
+       return NB_OK;
+}
+
+const void *pathd_srte_policy_candidate_path_lookup_entry(
+       struct nb_cb_lookup_entry_args *args)
+{
+       struct srte_policy *policy =
+               (struct srte_policy *)args->parent_list_entry;
+       uint32_t preference;
+
+       preference = yang_str2uint32(args->keys->key[0]);
+
+       return srte_candidate_find(policy, preference);
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/candidate_path/is-best-candidate-path
+ */
+struct yang_data *
+pathd_srte_policy_candidate_path_is_best_candidate_path_get_elem(
+       struct nb_cb_get_elem_args *args)
+{
+       struct srte_candidate *candidate =
+               (struct srte_candidate *)args->list_entry;
+
+       return yang_data_new_bool(
+               args->xpath, CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST));
+}
+
+/*
+ * XPath: /frr-pathd:pathd/srte/policy/candidate-path/discriminator
+ */
+struct yang_data *pathd_srte_policy_candidate_path_discriminator_get_elem(
+       struct nb_cb_get_elem_args *args)
+{
+       struct srte_candidate *candidate =
+               (struct srte_candidate *)args->list_entry;
+
+       return yang_data_new_uint32(args->xpath, candidate->discriminator);
+}
diff --git a/pathd/path_pcep.c b/pathd/path_pcep.c
new file mode 100644 (file)
index 0000000..2f9ff4f
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#include <zebra.h>
+#include <pcep_utils_counters.h>
+
+#include "log.h"
+#include "command.h"
+#include "libfrr.h"
+#include "printfrr.h"
+#include "version.h"
+#include "northbound.h"
+#include "frr_pthread.h"
+#include "jhash.h"
+#include "termtable.h"
+
+#include "pathd/pathd.h"
+#include "pathd/path_errors.h"
+#include "pathd/path_pcep_memory.h"
+#include "pathd/path_pcep.h"
+#include "pathd/path_pcep_cli.h"
+#include "pathd/path_pcep_controller.h"
+#include "pathd/path_pcep_lib.h"
+#include "pathd/path_pcep_config.h"
+
+
+/*
+ * Globals.
+ */
+static struct pcep_glob pcep_glob_space = {.dbg = {0, "pathd module: pcep"}};
+struct pcep_glob *pcep_g = &pcep_glob_space;
+
+/* Main Thread Even Handler */
+static int pcep_main_event_handler(enum pcep_main_event_type type, int pcc_id,
+                                  void *payload);
+static int pcep_main_event_start_sync(int pcc_id);
+static int pcep_main_event_start_sync_cb(struct path *path, void *arg);
+static int pcep_main_event_update_candidate(struct path *path);
+static int pcep_main_event_remove_candidate_segments(const char *originator,
+                                                    bool force);
+
+/* Hook Handlers called from the Main Thread */
+static int pathd_candidate_created_handler(struct srte_candidate *candidate);
+static int pathd_candidate_updated_handler(struct srte_candidate *candidate);
+static int pathd_candidate_removed_handler(struct srte_candidate *candidate);
+
+/* Path manipulation functions */
+static struct path_metric *pcep_copy_metrics(struct path_metric *metric);
+static struct path_hop *pcep_copy_hops(struct path_hop *hop);
+
+/* Module Functions */
+static int pcep_module_finish(void);
+static int pcep_module_late_init(struct thread_master *tm);
+static int pcep_module_init(void);
+
+/* ------------ Path Helper Functions ------------ */
+
+struct path *pcep_new_path(void)
+{
+       struct path *path;
+       path = XCALLOC(MTYPE_PCEP, sizeof(*path));
+       path->binding_sid = MPLS_LABEL_NONE;
+       path->enforce_bandwidth = true;
+       return path;
+}
+
+struct path_hop *pcep_new_hop(void)
+{
+       struct path_hop *hop;
+       hop = XCALLOC(MTYPE_PCEP, sizeof(*hop));
+       return hop;
+}
+
+struct path_metric *pcep_new_metric(void)
+{
+       struct path_metric *metric;
+       metric = XCALLOC(MTYPE_PCEP, sizeof(*metric));
+       return metric;
+}
+
+struct path_metric *pcep_copy_metrics(struct path_metric *metric)
+{
+       if (metric == NULL)
+               return NULL;
+       struct path_metric *new_metric = pcep_new_metric();
+       *new_metric = *metric;
+       new_metric->next = pcep_copy_metrics(metric->next);
+       return new_metric;
+}
+
+struct path_hop *pcep_copy_hops(struct path_hop *hop)
+{
+       if (hop == NULL)
+               return NULL;
+       struct path_hop *new_hop = pcep_new_hop();
+       *new_hop = *hop;
+       new_hop->next = pcep_copy_hops(hop->next);
+       return new_hop;
+}
+
+struct path *pcep_copy_path(struct path *path)
+{
+       struct path *new_path = pcep_new_path();
+
+       *new_path = *path;
+       new_path->first_metric = pcep_copy_metrics(path->first_metric);
+       new_path->first_hop = pcep_copy_hops(path->first_hop);
+       if (path->name != NULL)
+               new_path->name = XSTRDUP(MTYPE_PCEP, path->name);
+       if (path->originator != NULL)
+               new_path->originator = XSTRDUP(MTYPE_PCEP, path->originator);
+       return new_path;
+}
+
+void pcep_free_path(struct path *path)
+{
+       struct path_hop *hop;
+       struct path_metric *metric;
+       char *tmp;
+
+       metric = path->first_metric;
+       while (metric != NULL) {
+               struct path_metric *next = metric->next;
+               XFREE(MTYPE_PCEP, metric);
+               metric = next;
+       }
+       hop = path->first_hop;
+       while (hop != NULL) {
+               struct path_hop *next = hop->next;
+               XFREE(MTYPE_PCEP, hop);
+               hop = next;
+       }
+       if (path->originator != NULL) {
+               /* The path own the memory, it is const so it is clear it
+               shouldn't be modified. XFREE macro do not support type casting
+               so we need a temporary variable */
+               tmp = (char *)path->originator;
+               XFREE(MTYPE_PCEP, tmp);
+               path->originator = NULL;
+       }
+       if (path->name != NULL) {
+               /* The path own the memory, it is const so it is clear it
+               shouldn't be modified. XFREE macro do not support type casting
+               so we need a temporary variable */
+               tmp = (char *)path->name;
+               XFREE(MTYPE_PCEP, tmp);
+               path->name = NULL;
+       }
+       XFREE(MTYPE_PCEP, path);
+}
+
+
+/* ------------ Main Thread Even Handler ------------ */
+
+int pcep_main_event_handler(enum pcep_main_event_type type, int pcc_id,
+                           void *payload)
+{
+       int ret = 0;
+
+       switch (type) {
+       case PCEP_MAIN_EVENT_START_SYNC:
+               ret = pcep_main_event_start_sync(pcc_id);
+               break;
+       case PCEP_MAIN_EVENT_UPDATE_CANDIDATE:
+               assert(payload != NULL);
+               ret = pcep_main_event_update_candidate((struct path *)payload);
+               break;
+       case PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP:
+               ret = pcep_main_event_remove_candidate_segments(
+                       (const char *)payload, true);
+               break;
+       default:
+               flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
+                         "Unexpected event received in the main thread: %u",
+                         type);
+               break;
+       }
+
+       return ret;
+}
+
+int pcep_main_event_start_sync(int pcc_id)
+{
+       path_pcep_config_list_path(pcep_main_event_start_sync_cb, &pcc_id);
+       pcep_ctrl_sync_done(pcep_g->fpt, pcc_id);
+       return 0;
+}
+
+int pcep_main_event_start_sync_cb(struct path *path, void *arg)
+{
+       int *pcc_id = (int *)arg;
+       pcep_ctrl_sync_path(pcep_g->fpt, *pcc_id, path);
+       return 1;
+}
+
+int pcep_main_event_update_candidate(struct path *path)
+{
+       struct path *resp = NULL;
+       int ret = 0;
+
+       ret = path_pcep_config_update_path(path);
+       if (ret != PATH_NB_ERR && path->srp_id != 0) {
+               /* ODL and Cisco requires the first reported
+                * LSP to have a DOWN status, the later status changes
+                * will be comunicated through hook calls.
+                */
+               enum pcep_lsp_operational_status real_status;
+               if ((resp = path_pcep_config_get_path(&path->nbkey))) {
+                       resp->srp_id = path->srp_id;
+                       real_status = resp->status;
+                       resp->status = PCEP_LSP_OPERATIONAL_DOWN;
+                       pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id, resp);
+                       /* If the update did not have any effect and the real
+                        * status is not DOWN, we need to send a second report
+                        * so the PCE is aware of the real status. This is due
+                        * to the fact that NO notification will be received
+                        * if the update did not apply any changes */
+                       if ((ret == PATH_NB_NO_CHANGE)
+                           && (real_status != PCEP_LSP_OPERATIONAL_DOWN)) {
+                               resp->status = real_status;
+                               resp->srp_id = 0;
+                               pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id,
+                                                     resp);
+                       }
+                       pcep_free_path(resp);
+               }
+       }
+       return ret;
+}
+
+int pcep_main_event_remove_candidate_segments(const char *originator,
+                                             bool force)
+{
+       srte_candidate_unset_segment_list(originator, force);
+       /* Avoid compiler warnings about const char* */
+       void *free_ptr = (void *)originator;
+       XFREE(MTYPE_PCEP, free_ptr);
+
+       srte_apply_changes();
+
+       return 0;
+}
+
+/* ------------ Hook Handlers Functions Called From Main Thread ------------ */
+
+int pathd_candidate_created_handler(struct srte_candidate *candidate)
+{
+       struct path *path = candidate_to_path(candidate);
+       int ret = pcep_ctrl_pathd_event(pcep_g->fpt, PCEP_PATH_CREATED, path);
+       return ret;
+}
+
+int pathd_candidate_updated_handler(struct srte_candidate *candidate)
+{
+       struct path *path = candidate_to_path(candidate);
+       int ret = pcep_ctrl_pathd_event(pcep_g->fpt, PCEP_PATH_UPDATED, path);
+       return ret;
+}
+
+int pathd_candidate_removed_handler(struct srte_candidate *candidate)
+{
+       struct path *path = candidate_to_path(candidate);
+       int ret = pcep_ctrl_pathd_event(pcep_g->fpt, PCEP_PATH_REMOVED, path);
+       return ret;
+}
+
+
+/* ------------ Module Functions ------------ */
+
+int pcep_module_late_init(struct thread_master *tm)
+{
+       assert(pcep_g->fpt == NULL);
+       assert(pcep_g->master == NULL);
+
+       struct frr_pthread *fpt;
+
+       if (pcep_ctrl_initialize(tm, &fpt, pcep_main_event_handler))
+               return 1;
+
+       if (pcep_lib_initialize(fpt))
+               return 1;
+
+       pcep_g->master = tm;
+       pcep_g->fpt = fpt;
+
+       hook_register(pathd_candidate_created, pathd_candidate_created_handler);
+       hook_register(pathd_candidate_updated, pathd_candidate_updated_handler);
+       hook_register(pathd_candidate_removed, pathd_candidate_removed_handler);
+
+       hook_register(frr_fini, pcep_module_finish);
+
+       pcep_cli_init();
+
+       return 0;
+}
+
+int pcep_module_finish(void)
+{
+       pcep_ctrl_finalize(&pcep_g->fpt);
+       pcep_lib_finalize();
+
+       for (int i = 0; i < MAX_PCC; i++)
+               if (pcep_g->pce_opts_cli[i] != NULL)
+                       XFREE(MTYPE_PCEP, pcep_g->pce_opts_cli[i]);
+
+       return 0;
+}
+
+int pcep_module_init(void)
+{
+       pcep_g->num_pce_opts_cli = 0;
+       for (int i = 0; i < MAX_PCE; i++)
+               pcep_g->pce_opts_cli[i] = NULL;
+       pcep_g->num_config_group_opts = 0;
+       for (int i = 0; i < MAX_PCE; i++)
+               pcep_g->config_group_opts[i] = NULL;
+
+       hook_register(frr_late_init, pcep_module_late_init);
+       return 0;
+}
+
+FRR_MODULE_SETUP(.name = "frr_pathd_pcep", .version = FRR_VERSION,
+                .description = "FRR pathd PCEP module",
+                .init = pcep_module_init)
diff --git a/pathd/path_pcep.h b/pathd/path_pcep.h
new file mode 100644 (file)
index 0000000..1896c26
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#ifndef _PATH_PCEP_H_
+#define _PATH_PCEP_H_
+
+#include <stdbool.h>
+#include <debug.h>
+#include <netinet/tcp.h>
+#include <pcep_utils_logging.h>
+#include <pcep_pcc_api.h>
+#include "mpls.h"
+#include "pathd/pathd.h"
+#include "pathd/path_pcep_memory.h"
+
+#define PCEP_DEFAULT_PORT 4189
+#define MAX_PCC 32
+#define MAX_PCE 32
+#define MAX_TAG_SIZE 50
+#define PCEP_DEBUG_MODE_BASIC 0x01
+#define PCEP_DEBUG_MODE_PATH 0x02
+#define PCEP_DEBUG_MODE_PCEP 0x04
+#define PCEP_DEBUG_MODE_PCEPLIB 0x08
+#define PCEP_DEBUG(fmt, ...)                                                   \
+       do {                                                                   \
+               if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC))    \
+                       DEBUGD(&pcep_g->dbg, "pcep: " fmt, ##__VA_ARGS__);     \
+       } while (0)
+#define PCEP_DEBUG_PATH(fmt, ...)                                              \
+       do {                                                                   \
+               if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PATH))     \
+                       DEBUGD(&pcep_g->dbg, "pcep: " fmt, ##__VA_ARGS__);     \
+       } while (0)
+#define PCEP_DEBUG_PCEP(fmt, ...)                                              \
+       do {                                                                   \
+               if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEP))     \
+                       DEBUGD(&pcep_g->dbg, "pcep: " fmt, ##__VA_ARGS__);     \
+       } while (0)
+#define PCEP_DEBUG_PCEPLIB(priority, fmt, ...)                                 \
+       do {                                                                   \
+               switch (priority) {                                            \
+               case LOG_DEBUG:                                                \
+                       if (DEBUG_FLAGS_CHECK(&pcep_g->dbg,                    \
+                                             PCEP_DEBUG_MODE_PCEPLIB))        \
+                               DEBUGD(&pcep_g->dbg, "pcep: " fmt,             \
+                                      ##__VA_ARGS__);                         \
+                       break;                                                 \
+               case LOG_INFO:                                                 \
+                       if (DEBUG_FLAGS_CHECK(&pcep_g->dbg,                    \
+                                             PCEP_DEBUG_MODE_PCEPLIB))        \
+                               DEBUGI(&pcep_g->dbg, "pcep: " fmt,             \
+                                      ##__VA_ARGS__);                         \
+                       break;                                                 \
+               case LOG_NOTICE:                                               \
+                       if (DEBUG_FLAGS_CHECK(&pcep_g->dbg,                    \
+                                             PCEP_DEBUG_MODE_PCEPLIB))        \
+                               DEBUGN(&pcep_g->dbg, "pcep: " fmt,             \
+                                      ##__VA_ARGS__);                         \
+                       break;                                                 \
+               case LOG_WARNING:                                              \
+               case LOG_ERR:                                                  \
+               default:                                                       \
+                       zlog(priority, "pcep: " fmt, ##__VA_ARGS__);           \
+                       break;                                                 \
+               }                                                              \
+       } while (0)
+
+struct pcep_config_group_opts {
+       char name[64];
+       char tcp_md5_auth[TCP_MD5SIG_MAXKEYLEN];
+       struct ipaddr source_ip;
+       short source_port;
+       bool draft07;
+       bool pce_initiated;
+       int keep_alive_seconds;
+       int min_keep_alive_seconds;
+       int max_keep_alive_seconds;
+       int dead_timer_seconds;
+       int min_dead_timer_seconds;
+       int max_dead_timer_seconds;
+       int pcep_request_time_seconds;
+       int session_timeout_inteval_seconds;
+       int delegation_timeout_seconds;
+};
+
+struct pce_opts {
+       struct ipaddr addr;
+       short port;
+       char pce_name[64];
+       struct pcep_config_group_opts config_opts;
+       uint8_t precedence; /* Multi-PCE precedence */
+};
+
+struct pcc_opts {
+       struct ipaddr addr;
+       short port;
+       short msd;
+};
+
+/* Encapsulate the pce_opts with needed CLI information */
+struct pce_opts_cli {
+       struct pce_opts pce_opts;
+       char config_group_name[64];
+       /* These are the values configured in the pcc-peer sub-commands.
+        * These need to be stored for later merging. Notice, it could
+        * be that not all of them are set. */
+       struct pcep_config_group_opts pce_config_group_opts;
+       /* The pce_opts->config_opts will be a merge of the default values,
+        * optional config_group values (which overwrite default values),
+        * and any values configured in the pce sub-commands (which overwrite
+        * both default and config_group values). This flag indicates of the
+        * values need to be merged or not. */
+       bool merged;
+};
+
+struct lsp_nb_key {
+       uint32_t color;
+       struct ipaddr endpoint;
+       uint32_t preference;
+};
+
+struct sid_mpls {
+       mpls_label_t label;
+       uint8_t traffic_class;
+       bool is_bottom;
+       uint8_t ttl;
+};
+
+struct pcep_caps {
+       bool is_stateful;
+       /* If we know the objective functions supported by the PCE.
+        * If we don't know, it doesn't mean the PCE doesn't support any */
+       bool supported_ofs_are_known;
+       /* Defined if we know which objective funtions are supported by the PCE.
+        * One bit per objective function, the bit index being equal to
+        * enum pcep_objfun_type values: bit 0 is not used, bit 1 is
+        * PCEP_OBJFUN_MCP, up to bit 17 that is PCEP_OBJFUN_MSN */
+       uint32_t supported_ofs;
+};
+
+union sid {
+       uint32_t value;
+       struct sid_mpls mpls;
+};
+
+struct nai {
+       /* NAI type */
+       enum pcep_sr_subobj_nai type;
+       /* Local IP address*/
+       struct ipaddr local_addr;
+       /* Local interface identifier if the NAI is an unnumbered adjacency */
+       uint32_t local_iface;
+       /* Remote address if the NAI is an adjacency */
+       struct ipaddr remote_addr;
+       /* Remote interface identifier if the NAI is an unnumbered adjacency */
+       uint32_t remote_iface;
+};
+
+struct path_hop {
+       /* Pointer to the next hop in the path */
+       struct path_hop *next;
+       /* Indicateif this ia a loose or strict hop */
+       bool is_loose;
+       /* Indicate if there is an SID for the hop */
+       bool has_sid;
+       /* Indicate if the hop as a MPLS label */
+       bool is_mpls;
+       /* Indicate if the MPLS label has extra attributes (TTL, class..)*/
+       bool has_attribs;
+       /* Hop's SID if available */
+       union sid sid;
+       /* Indicate if there is a NAI for this hop */
+       bool has_nai;
+       /* NAI if available */
+       struct nai nai;
+};
+
+struct path_metric {
+       /* Pointer to the next metric */
+       struct path_metric *next;
+       /* The metric type */
+       enum pcep_metric_types type;
+       /* If the metric should be enforced */
+       bool enforce;
+       /* If the metric value is bound (a maximum) */
+       bool is_bound;
+       /* If the metric value is computed */
+       bool is_computed;
+       /* The metric value */
+       float value;
+};
+
+struct path {
+       /* Both the nbkey and the plspid are keys comming from the PCC,
+       but the PCE is only using the plspid. The missing key is looked up by
+       the PCC so we always have both */
+
+       /* The northbound key identifying this path */
+       struct lsp_nb_key nbkey;
+       /* The generated unique PLSP identifier for this path.
+          See draft-ietf-pce-stateful-pce */
+       uint32_t plsp_id;
+
+       /* The transport address the path is comming from, PCE or PCC*/
+       struct ipaddr sender;
+       /* The pcc protocol address, must be the same family as the endpoint */
+       struct ipaddr pcc_addr;
+
+       /* The identifier of the PCC the path is for/from. If 0 it is undefined,
+       meaning it hasn't be set yet or is for all the PCC */
+       int pcc_id;
+
+       /* The origin of the path creation */
+       enum srte_protocol_origin create_origin;
+       /* The origin of the path modification */
+       enum srte_protocol_origin update_origin;
+       /* The identifier of the entity that originated the path */
+       const char *originator;
+       /* The type of the path, for PCE initiated or updated path it is always
+       SRTE_CANDIDATE_TYPE_DYNAMIC */
+       enum srte_candidate_type type;
+
+       /* The following data comes from either the PCC or the PCE if available
+        */
+
+       /* Path's binding SID */
+       mpls_label_t binding_sid;
+       /* The name of the path */
+       const char *name;
+       /* The request identifier from the PCE, when getting a path from the
+          PCE. See draft-ietf-pce-stateful-pce */
+       uint32_t srp_id;
+       /* The request identifier from the PCC , when getting a path from the
+          PCE after a computation request. See rfc5440, section-7.4 */
+       uint32_t req_id;
+       /* The operational status of the path */
+       enum pcep_lsp_operational_status status;
+       /* If true, the receiver (PCC) must remove the path.
+          See draft-ietf-pce-pce-initiated-lsp */
+       bool do_remove;
+       /* Indicate the given path was removed by the PCC.
+          See draft-ietf-pce-stateful-pce, section-7.3, flag R */
+       bool was_removed;
+       /* Indicate the path is part of the synchronization process.
+          See draft-ietf-pce-stateful-pce, section-7.3, flag S */
+       bool is_synching;
+       /* Indicate if the path bandwidth requirment is defined */
+       bool has_bandwidth;
+       /* Indicate if the bandwidth requirment should be enforced */
+       bool enforce_bandwidth;
+       /* Path required bandwidth if defined */
+       float bandwidth;
+       /* Specify the list of hop defining the path */
+       struct path_hop *first_hop;
+       /* Specify the list of metrics */
+       struct path_metric *first_metric;
+       /* Indicate if the path has a PCC-defined objective function */
+       bool has_pcc_objfun;
+       /* Indicate the PCC-defined objective function is required */
+       bool enforce_pcc_objfun;
+       /* PCC-defined Objective Function */
+       enum objfun_type pcc_objfun;
+       /* Indicate if the path has a PCE-defined objective function */
+       bool has_pce_objfun;
+       /* PCE-defined Objective Function */
+       enum objfun_type pce_objfun;
+       /* Indicate if some affinity filters are defined */
+       bool has_affinity_filters;
+       /* Affinity attribute filters indexed by enum affinity_filter_type - 1
+        */
+       uint32_t affinity_filters[MAX_AFFINITY_FILTER_TYPE];
+
+       /* The following data need to be specialized for a given PCE */
+
+       /* Indicate the path is delegated to the PCE.
+          See draft-ietf-pce-stateful-pce, section-7.3, flag D */
+       bool is_delegated;
+       /* Indicate if the PCE wants the path to get active.
+          See draft-ietf-pce-stateful-pce, section-7.3, flag A */
+       bool go_active;
+       /* Indicate the given path was created by the PCE,
+          See draft-ietf-pce-pce-initiated-lsp, section-5.3.1, flag C */
+       bool was_created;
+
+       /* The following data is defined for comnputation replies */
+
+       /* Indicate that no path could be computed */
+       bool no_path;
+};
+
+struct pcep_glob {
+       struct debug dbg;
+       struct thread_master *master;
+       struct frr_pthread *fpt;
+       uint8_t num_pce_opts_cli;
+       struct pce_opts_cli *pce_opts_cli[MAX_PCE];
+       uint8_t num_config_group_opts;
+       struct pcep_config_group_opts *config_group_opts[MAX_PCE];
+};
+
+extern struct pcep_glob *pcep_g;
+
+/* Path Helper Functions */
+struct path *pcep_new_path(void);
+struct path_hop *pcep_new_hop(void);
+struct path_metric *pcep_new_metric(void);
+struct path *pcep_copy_path(struct path *path);
+void pcep_free_path(struct path *path);
+
+
+#endif // _PATH_PCEP_H_
diff --git a/pathd/path_pcep_cli.c b/pathd/path_pcep_cli.c
new file mode 100644 (file)
index 0000000..add3391
--- /dev/null
@@ -0,0 +1,2033 @@
+/*
+ * Copyright (C) 2020 Volta Networks, Inc
+ *                     Brady Johnson
+ *
+ * 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 <pcep_utils_counters.h>
+#include <pcep_session_logic.h>
+
+#include "log.h"
+#include "command.h"
+#include "libfrr.h"
+#include "printfrr.h"
+#include "version.h"
+#include "northbound.h"
+#include "frr_pthread.h"
+#include "jhash.h"
+#include "termtable.h"
+
+#include "pathd/pathd.h"
+#include "pathd/path_errors.h"
+#include "pathd/path_pcep_memory.h"
+#include "pathd/path_pcep.h"
+#include "pathd/path_pcep_cli.h"
+#include "pathd/path_pcep_controller.h"
+#include "pathd/path_pcep_debug.h"
+#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
+#define DEFAULT_SR_DRAFT07 false
+#define DEFAULT_PCE_INITIATED false
+#define DEFAULT_TIMER_KEEP_ALIVE 30
+#define DEFAULT_TIMER_KEEP_ALIVE_MIN 1
+#define DEFAULT_TIMER_KEEP_ALIVE_MAX 255
+#define DEFAULT_TIMER_DEADTIMER 120
+#define DEFAULT_TIMER_DEADTIMER_MIN 4
+#define DEFAULT_TIMER_DEADTIMER_MAX 255
+#define DEFAULT_TIMER_PCEP_REQUEST 30
+#define DEFAULT_TIMER_SESSION_TIMEOUT_INTERVAL 30
+#define DEFAULT_DELEGATION_TIMEOUT_INTERVAL 10
+
+/* CLI Function declarations */
+static int pcep_cli_debug_config_write(struct vty *vty);
+static int pcep_cli_debug_set_all(uint32_t flags, bool set);
+static int pcep_cli_pcep_config_write(struct vty *vty);
+static int pcep_cli_pcc_config_write(struct vty *vty);
+static int pcep_cli_pce_config_write(struct vty *vty);
+static int pcep_cli_pcep_pce_config_write(struct vty *vty);
+
+/* Internal Util Function declarations */
+static struct pce_opts_cli *pcep_cli_find_pce(const char *pce_name);
+static bool pcep_cli_add_pce(struct pce_opts_cli *pce_opts_cli);
+static struct pce_opts_cli *pcep_cli_create_pce_opts();
+static void pcep_cli_delete_pce(const char *pce_name);
+static void
+pcep_cli_merge_pcep_pce_config_options(struct pce_opts_cli *pce_opts_cli);
+static struct pcep_config_group_opts *
+pcep_cli_find_pcep_pce_config(const char *group_name);
+static bool
+pcep_cli_add_pcep_pce_config(struct pcep_config_group_opts *config_group_opts);
+static struct pcep_config_group_opts *
+pcep_cli_create_pcep_pce_config(const char *group_name);
+static bool pcep_cli_is_pcep_pce_config_used(const char *group_name);
+static void pcep_cli_delete_pcep_pce_config(const char *group_name);
+static int pcep_cli_print_pce_config(struct pcep_config_group_opts *group_opts,
+                                    char *buf, size_t buf_len);
+static void print_pcep_capabilities(char *buf, size_t buf_len,
+                                   pcep_configuration *config);
+static void print_pcep_session(struct vty *vty, struct pce_opts *pce_opts,
+                              struct pcep_pcc_info *pcc_info);
+static bool pcep_cli_pcc_has_pce(const char *pce_name);
+static void pcep_cli_add_pce_connection(struct pce_opts *pce_opts);
+static void pcep_cli_remove_pce_connection(struct pce_opts *pce_opts);
+static int path_pcep_cli_pcc_pcc_peer_delete(struct vty *vty,
+                                            const char *peer_name,
+                                            const char *precedence_str,
+                                            long precedence);
+
+/*
+ * Globals.
+ */
+
+static const char PCEP_VTYSH_ARG_ADDRESS[] = "address";
+static const char PCEP_VTYSH_ARG_SOURCE_ADDRESS[] = "source-address";
+static const char PCEP_VTYSH_ARG_IP[] = "ip";
+static const char PCEP_VTYSH_ARG_IPV6[] = "ipv6";
+static const char PCEP_VTYSH_ARG_PORT[] = "port";
+static const char PCEP_VTYSH_ARG_PRECEDENCE[] = "precedence";
+static const char PCEP_VTYSH_ARG_MSD[] = "msd";
+static const char PCEP_VTYSH_ARG_KEEP_ALIVE[] = "keep-alive";
+static const char PCEP_VTYSH_ARG_TIMER[] = "timer";
+static const char PCEP_VTYSH_ARG_KEEP_ALIVE_MIN[] = "min-peer-keep-alive";
+static const char PCEP_VTYSH_ARG_KEEP_ALIVE_MAX[] = "max-peer-keep-alive";
+static const char PCEP_VTYSH_ARG_DEAD_TIMER[] = "dead-timer";
+static const char PCEP_VTYSH_ARG_DEAD_TIMER_MIN[] = "min-peer-dead-timer";
+static const char PCEP_VTYSH_ARG_DEAD_TIMER_MAX[] = "max-peer-dead-timer";
+static const char PCEP_VTYSH_ARG_PCEP_REQUEST[] = "pcep-request";
+static const char PCEP_VTYSH_ARG_SESSION_TIMEOUT[] = "session-timeout-interval";
+static const char PCEP_VTYSH_ARG_DELEGATION_TIMEOUT[] = "delegation-timeout";
+static const char PCEP_VTYSH_ARG_SR_DRAFT07[] = "sr-draft07";
+static const char PCEP_VTYSH_ARG_PCE_INIT[] = "pce-initiated";
+static const char PCEP_VTYSH_ARG_TCP_MD5[] = "tcp-md5-auth";
+static const char PCEP_VTYSH_ARG_BASIC[] = "basic";
+static const char PCEP_VTYSH_ARG_PATH[] = "path";
+static const char PCEP_VTYSH_ARG_MESSAGE[] = "message";
+static const char PCEP_VTYSH_ARG_PCEPLIB[] = "pceplib";
+static const char PCEP_CLI_CAP_STATEFUL[] = " [Stateful PCE]";
+static const char PCEP_CLI_CAP_INCL_DB_VER[] = " [Include DB version]";
+static const char PCEP_CLI_CAP_LSP_TRIGGERED[] = " [LSP Triggered Resync]";
+static const char PCEP_CLI_CAP_LSP_DELTA[] = " [LSP Delta Sync]";
+static const char PCEP_CLI_CAP_PCE_TRIGGERED[] =
+       " [PCE triggered Initial Sync]";
+static const char PCEP_CLI_CAP_SR_TE_PST[] = " [SR TE PST]";
+static const char PCEP_CLI_CAP_PCC_RESOLVE_NAI[] =
+       " [PCC can resolve NAI to SID]";
+static const char PCEP_CLI_CAP_PCC_INITIATED[] = " [PCC Initiated LSPs]";
+static const char PCEP_CLI_CAP_PCC_PCE_INITIATED[] =
+       " [PCC and PCE Initiated LSPs]";
+
+struct pce_connections {
+       int num_connections;
+       struct pce_opts *connections[MAX_PCC];
+};
+
+struct pce_connections pce_connections_g = {.num_connections = 0};
+
+/* Default PCE group that all PCE-Groups and PCEs will inherit from */
+struct pcep_config_group_opts default_pcep_config_group_opts_g = {
+       .name = "default",
+       .tcp_md5_auth = "\0",
+       .draft07 = DEFAULT_SR_DRAFT07,
+       .pce_initiated = DEFAULT_PCE_INITIATED,
+       .keep_alive_seconds = DEFAULT_TIMER_KEEP_ALIVE,
+       .min_keep_alive_seconds = DEFAULT_TIMER_KEEP_ALIVE_MIN,
+       .max_keep_alive_seconds = DEFAULT_TIMER_KEEP_ALIVE_MAX,
+       .dead_timer_seconds = DEFAULT_TIMER_DEADTIMER,
+       .min_dead_timer_seconds = DEFAULT_TIMER_DEADTIMER_MIN,
+       .max_dead_timer_seconds = DEFAULT_TIMER_DEADTIMER_MAX,
+       .pcep_request_time_seconds = DEFAULT_TIMER_PCEP_REQUEST,
+       .session_timeout_inteval_seconds =
+               DEFAULT_TIMER_SESSION_TIMEOUT_INTERVAL,
+       .delegation_timeout_seconds = DEFAULT_DELEGATION_TIMEOUT_INTERVAL,
+       .source_port = DEFAULT_PCEP_TCP_PORT,
+       .source_ip.ipa_type = IPADDR_NONE,
+};
+
+/* Used by PCEP_PCE_CONFIG_NODE sub-commands to operate on the current pce group
+ */
+struct pcep_config_group_opts *current_pcep_config_group_opts_g = NULL;
+/* Used by PCEP_PCE_NODE sub-commands to operate on the current pce opts */
+struct pce_opts_cli *current_pce_opts_g = NULL;
+short pcc_msd_g = DEFAULT_PCC_MSD;
+bool pcc_msd_configured_g = false;
+
+static struct cmd_node pcep_node = {
+       .name = "srte pcep",
+       .node = PCEP_NODE,
+       .parent_node = SR_TRAFFIC_ENG_NODE,
+       .config_write = pcep_cli_pcep_config_write,
+       .prompt = "%s(config-sr-te-pcep)# "
+};
+
+static struct cmd_node pcep_pcc_node = {
+       .name = "srte pcep pcc",
+       .node = PCEP_PCC_NODE,
+       .parent_node = PCEP_NODE,
+       .config_write = pcep_cli_pcc_config_write,
+       .prompt = "%s(config-sr-te-pcep-pcc)# "
+};
+
+static struct cmd_node pcep_pce_node = {
+       .name = "srte pcep pce",
+       .node = PCEP_PCE_NODE,
+       .parent_node = PCEP_NODE,
+       .config_write = pcep_cli_pce_config_write,
+       .prompt = "%s(config-sr-te-pcep-pce)# "
+};
+
+static struct cmd_node pcep_pce_config_node = {
+       .name = "srte pcep pce-config",
+       .node = PCEP_PCE_CONFIG_NODE,
+       .parent_node = PCEP_NODE,
+       .config_write = pcep_cli_pcep_pce_config_write,
+       .prompt = "%s(pce-sr-te-pcep-pce-config)# "
+};
+
+/* Common code used in VTYSH processing for int values */
+#define PCEP_VTYSH_INT_ARG_CHECK(arg_str, arg_val, arg_store, min_value,       \
+                                max_value)                                    \
+       if (arg_str != NULL) {                                                 \
+               if (arg_val <= min_value || arg_val >= max_value) {            \
+                       vty_out(vty,                                           \
+                               "%% Invalid value %ld in range [%d - %d]",     \
+                               arg_val, min_value, max_value);                \
+                       return CMD_WARNING;                                    \
+               }                                                              \
+               arg_store = arg_val;                                           \
+       }
+
+#define MERGE_COMPARE_CONFIG_GROUP_VALUE(config_param, not_set_value)          \
+       pce_opts_cli->pce_opts.config_opts.config_param =                      \
+               pce_opts_cli->pce_config_group_opts.config_param;              \
+       if (pce_opts_cli->pce_config_group_opts.config_param                   \
+           == not_set_value) {                                                \
+               pce_opts_cli->pce_opts.config_opts.config_param =              \
+                       ((pce_config != NULL                                   \
+                         && pce_config->config_param != not_set_value)        \
+                                ? pce_config->config_param                    \
+                                : default_pcep_config_group_opts_g            \
+                                          .config_param);                     \
+       }
+
+/*
+ * Internal Util functions
+ */
+
+/* Check if a pce_opts_cli already exists based on its name and return it,
+ * return NULL otherwise */
+static struct pce_opts_cli *pcep_cli_find_pce(const char *pce_name)
+{
+       for (int i = 0; i < MAX_PCE; i++) {
+               struct pce_opts_cli *pce_rhs_cli = pcep_g->pce_opts_cli[i];
+               if (pce_rhs_cli != NULL) {
+                       if (strcmp(pce_name, pce_rhs_cli->pce_opts.pce_name)
+                           == 0) {
+                               return pce_rhs_cli;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+/* Add a new pce_opts_cli to pcep_g, return false if MAX_PCES, true otherwise */
+static bool pcep_cli_add_pce(struct pce_opts_cli *pce_opts_cli)
+{
+       for (int i = 0; i < MAX_PCE; i++) {
+               if (pcep_g->pce_opts_cli[i] == NULL) {
+                       pcep_g->pce_opts_cli[i] = pce_opts_cli;
+                       pcep_g->num_pce_opts_cli++;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+/* Create a new pce opts_cli */
+static struct pce_opts_cli *pcep_cli_create_pce_opts(const char *name)
+{
+       struct pce_opts_cli *pce_opts_cli =
+               XCALLOC(MTYPE_PCEP, sizeof(struct pce_opts_cli));
+       strlcpy(pce_opts_cli->pce_opts.pce_name, name,
+               sizeof(pce_opts_cli->pce_opts.pce_name));
+       pce_opts_cli->pce_opts.port = PCEP_DEFAULT_PORT;
+
+       return pce_opts_cli;
+}
+
+static void pcep_cli_delete_pce(const char *pce_name)
+{
+       for (int i = 0; i < MAX_PCE; i++) {
+               if (pcep_g->pce_opts_cli[i] != NULL) {
+                       if (strcmp(pcep_g->pce_opts_cli[i]->pce_opts.pce_name,
+                                  pce_name)
+                           == 0) {
+                               XFREE(MTYPE_PCEP, pcep_g->pce_opts_cli[i]);
+                               pcep_g->pce_opts_cli[i] = NULL;
+                               pcep_g->num_pce_opts_cli--;
+                               return;
+                       }
+               }
+       }
+}
+
+static void
+pcep_cli_merge_pcep_pce_config_options(struct pce_opts_cli *pce_opts_cli)
+{
+       if (pce_opts_cli->merged == true) {
+               return;
+       }
+
+       struct pcep_config_group_opts *pce_config =
+               pcep_cli_find_pcep_pce_config(pce_opts_cli->config_group_name);
+
+       /* Configuration priorities:
+        * 1) pce_opts->config_opts, if present, overwrite pce_config
+        * config_opts 2) pce_config config_opts, if present, overwrite
+        * default config_opts 3) If neither pce_opts->config_opts nor
+        * pce_config config_opts are set, then the default config_opts value
+        * will be used.
+        */
+
+       const char *tcp_md5_auth_str =
+               pce_opts_cli->pce_config_group_opts.tcp_md5_auth;
+       if (pce_opts_cli->pce_config_group_opts.tcp_md5_auth[0] == '\0') {
+               if (pce_config != NULL && pce_config->tcp_md5_auth[0] != '\0') {
+                       tcp_md5_auth_str = pce_config->tcp_md5_auth;
+               } else {
+                       tcp_md5_auth_str =
+                               default_pcep_config_group_opts_g.tcp_md5_auth;
+               }
+       }
+       strncpy(pce_opts_cli->pce_opts.config_opts.tcp_md5_auth,
+               tcp_md5_auth_str, TCP_MD5SIG_MAXKEYLEN);
+
+       struct ipaddr *source_ip =
+               &pce_opts_cli->pce_config_group_opts.source_ip;
+       if (pce_opts_cli->pce_config_group_opts.source_ip.ipa_type
+           == IPADDR_NONE) {
+               if (pce_config != NULL
+                   && pce_config->source_ip.ipa_type != IPADDR_NONE) {
+                       source_ip = &pce_config->source_ip;
+               } else {
+                       source_ip = &default_pcep_config_group_opts_g.source_ip;
+               }
+       }
+       memcpy(&pce_opts_cli->pce_opts.config_opts.source_ip, source_ip,
+              sizeof(struct ipaddr));
+
+       MERGE_COMPARE_CONFIG_GROUP_VALUE(draft07, false);
+       MERGE_COMPARE_CONFIG_GROUP_VALUE(pce_initiated, false);
+       MERGE_COMPARE_CONFIG_GROUP_VALUE(keep_alive_seconds, 0);
+       MERGE_COMPARE_CONFIG_GROUP_VALUE(min_keep_alive_seconds, 0);
+       MERGE_COMPARE_CONFIG_GROUP_VALUE(max_keep_alive_seconds, 0);
+       MERGE_COMPARE_CONFIG_GROUP_VALUE(dead_timer_seconds, 0);
+       MERGE_COMPARE_CONFIG_GROUP_VALUE(min_dead_timer_seconds, 0);
+       MERGE_COMPARE_CONFIG_GROUP_VALUE(max_dead_timer_seconds, 0);
+       MERGE_COMPARE_CONFIG_GROUP_VALUE(pcep_request_time_seconds, 0);
+       MERGE_COMPARE_CONFIG_GROUP_VALUE(session_timeout_inteval_seconds, 0);
+       MERGE_COMPARE_CONFIG_GROUP_VALUE(delegation_timeout_seconds, 0);
+       MERGE_COMPARE_CONFIG_GROUP_VALUE(source_port, 0);
+
+       pce_opts_cli->merged = true;
+}
+
+/* Check if a pcep_config_group_opts already exists based on its name and return
+ * it, return NULL otherwise */
+static struct pcep_config_group_opts *
+pcep_cli_find_pcep_pce_config(const char *group_name)
+{
+       for (int i = 0; i < MAX_PCE; i++) {
+               struct pcep_config_group_opts *pcep_pce_config_rhs =
+                       pcep_g->config_group_opts[i];
+               if (pcep_pce_config_rhs != NULL) {
+                       if (strcmp(group_name, pcep_pce_config_rhs->name)
+                           == 0) {
+                               return pcep_pce_config_rhs;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+/* Add a new pcep_config_group_opts to pcep_g, return false if MAX_PCE,
+ * true otherwise */
+static bool pcep_cli_add_pcep_pce_config(
+       struct pcep_config_group_opts *pcep_config_group_opts)
+{
+       for (int i = 0; i < MAX_PCE; i++) {
+               if (pcep_g->config_group_opts[i] == NULL) {
+                       pcep_g->config_group_opts[i] = pcep_config_group_opts;
+                       pcep_g->num_config_group_opts++;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+/* Create a new pce group, inheriting its values from the default pce group */
+static struct pcep_config_group_opts *
+pcep_cli_create_pcep_pce_config(const char *group_name)
+{
+       struct pcep_config_group_opts *pcep_config_group_opts =
+               XCALLOC(MTYPE_PCEP, sizeof(struct pcep_config_group_opts));
+       strlcpy(pcep_config_group_opts->name, group_name,
+               sizeof(pcep_config_group_opts->name));
+
+       return pcep_config_group_opts;
+}
+
+/* Iterate the pce_opts and return true if the pce-group-name is referenced,
+ * false otherwise. */
+static bool pcep_cli_is_pcep_pce_config_used(const char *group_name)
+{
+       for (int i = 0; i < MAX_PCE; i++) {
+               if (pcep_g->pce_opts_cli[i] != NULL) {
+                       if (strcmp(pcep_g->pce_opts_cli[i]->config_group_name,
+                                  group_name)
+                           == 0) {
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+static void pcep_cli_delete_pcep_pce_config(const char *group_name)
+{
+       for (int i = 0; i < MAX_PCE; i++) {
+               if (pcep_g->config_group_opts[i] != NULL) {
+                       if (strcmp(pcep_g->config_group_opts[i]->name,
+                                  group_name)
+                           == 0) {
+                               XFREE(MTYPE_PCEP, pcep_g->config_group_opts[i]);
+                               pcep_g->config_group_opts[i] = NULL;
+                               pcep_g->num_config_group_opts--;
+                               return;
+                       }
+               }
+       }
+}
+
+static bool pcep_cli_pcc_has_pce(const char *pce_name)
+{
+       for (int i = 0; i < MAX_PCC; i++) {
+               struct pce_opts *pce_opts = pce_connections_g.connections[i];
+               if (pce_opts == NULL) {
+                       continue;
+               }
+
+               if (strcmp(pce_opts->pce_name, pce_name) == 0) {
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static void pcep_cli_add_pce_connection(struct pce_opts *pce_opts)
+{
+       for (int i = 0; i < MAX_PCC; i++) {
+               if (pce_connections_g.connections[i] == NULL) {
+                       pce_connections_g.num_connections++;
+                       pce_connections_g.connections[i] = pce_opts;
+                       return;
+               }
+       }
+}
+
+static void pcep_cli_remove_pce_connection(struct pce_opts *pce_opts)
+{
+       for (int i = 0; i < MAX_PCC; i++) {
+               if (pce_connections_g.connections[i] == pce_opts) {
+                       pce_connections_g.num_connections--;
+                       pce_connections_g.connections[i] = NULL;
+                       return;
+               }
+       }
+}
+
+/*
+ * VTY command implementations
+ */
+
+static int path_pcep_cli_debug(struct vty *vty, const char *no_str,
+                              const char *basic_str, const char *path_str,
+                              const char *message_str, const char *pceplib_str)
+{
+       uint32_t mode = DEBUG_NODE2MODE(vty->node);
+       bool no = (no_str != NULL);
+
+       DEBUG_MODE_SET(&pcep_g->dbg, mode, !no);
+
+       if (basic_str != NULL) {
+               DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC, !no);
+       }
+       if (path_str != NULL) {
+               DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PATH, !no);
+       }
+       if (message_str != NULL) {
+               DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEP, !no);
+       }
+       if (pceplib_str != NULL) {
+               DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEPLIB, !no);
+       }
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_show_srte_pcep_counters(struct vty *vty)
+{
+       int i, j, row;
+       time_t diff_time;
+       struct tm *tm_info;
+       char tm_buffer[26];
+       struct counters_group *group;
+       struct counters_subgroup *subgroup;
+       struct counter *counter;
+       const char *group_name, *empty_string = "";
+       struct ttable *tt;
+       char *table;
+
+       group = pcep_ctrl_get_counters(pcep_g->fpt, 1);
+
+       if (group == NULL) {
+               vty_out(vty, "No counters to display.\n\n");
+               return CMD_SUCCESS;
+       }
+
+       diff_time = time(NULL) - group->start_time;
+       tm_info = localtime(&group->start_time);
+       strftime(tm_buffer, sizeof(tm_buffer), "%Y-%m-%d %H:%M:%S", tm_info);
+
+       vty_out(vty, "PCEP counters since %s (%luh %lum %lus):\n", tm_buffer,
+               diff_time / 3600, (diff_time / 60) % 60, diff_time % 60);
+
+       /* Prepare table. */
+       tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+       ttable_add_row(tt, "Group|Name|Value");
+       tt->style.cell.rpad = 2;
+       tt->style.corner = '+';
+       ttable_restyle(tt);
+       ttable_rowseps(tt, 0, BOTTOM, true, '-');
+
+       for (row = 0, i = 0; i <= group->num_subgroups; i++) {
+               subgroup = group->subgroups[i];
+               if (subgroup != NULL) {
+                       group_name = subgroup->counters_subgroup_name;
+                       for (j = 0; j <= subgroup->num_counters; j++) {
+                               counter = subgroup->counters[j];
+                               if (counter != NULL) {
+                                       ttable_add_row(tt, "%s|%s|%u",
+                                                      group_name,
+                                                      counter->counter_name,
+                                                      counter->counter_value);
+                                       row++;
+                                       group_name = empty_string;
+                               }
+                       }
+                       ttable_rowseps(tt, row, BOTTOM, true, '-');
+               }
+       }
+
+       /* Dump the generated table. */
+       table = ttable_dump(tt, "\n");
+       vty_out(vty, "%s\n", table);
+       XFREE(MTYPE_TMP, table);
+
+       ttable_del(tt);
+
+       pcep_lib_free_counters(group);
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pcep_pce_config(struct vty *vty,
+                                        const char *pcep_pce_config)
+{
+       struct pcep_config_group_opts *pce_config =
+               pcep_cli_find_pcep_pce_config(pcep_pce_config);
+       if (pce_config == NULL) {
+               pce_config = pcep_cli_create_pcep_pce_config(pcep_pce_config);
+               if (pcep_cli_add_pcep_pce_config(pce_config) == false) {
+                       vty_out(vty,
+                               "%% Cannot create pce-config, as the Maximum limit of %d pce-config has been reached.\n",
+                               MAX_PCE);
+                       XFREE(MTYPE_PCEP, pce_config);
+                       return CMD_WARNING;
+               }
+       } else {
+               vty_out(vty,
+                       "Notice: changes to this pce-config will not affect PCEs already configured with this group\n");
+       }
+
+       current_pcep_config_group_opts_g = pce_config;
+       vty->node = PCEP_PCE_CONFIG_NODE;
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pcep_pce_config_delete(struct vty *vty,
+                                               const char *pcep_pce_config)
+{
+       struct pcep_config_group_opts *pce_config =
+               pcep_cli_find_pcep_pce_config(pcep_pce_config);
+       if (pce_config == NULL) {
+               vty_out(vty,
+                       "%% Cannot delete pce-config, since it does not exist.\n");
+               return CMD_WARNING;
+       }
+
+       if (pcep_cli_is_pcep_pce_config_used(pce_config->name)) {
+               vty_out(vty,
+                       "%% Cannot delete pce-config, since it is in use by a peer.\n");
+               return CMD_WARNING;
+       }
+
+       pcep_cli_delete_pcep_pce_config(pce_config->name);
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_show_srte_pcep_pce_config(struct vty *vty,
+                                                  const char *pcep_pce_config)
+{
+       char buf[1024] = "";
+
+       /* Only show 1 Peer config group */
+       struct pcep_config_group_opts *group_opts;
+       if (pcep_pce_config != NULL) {
+               if (strcmp(pcep_pce_config, "default") == 0) {
+                       group_opts = &default_pcep_config_group_opts_g;
+               } else {
+                       group_opts =
+                               pcep_cli_find_pcep_pce_config(pcep_pce_config);
+               }
+               if (group_opts == NULL) {
+                       vty_out(vty, "%% pce-config [%s] does not exist.\n",
+                               pcep_pce_config);
+                       return CMD_WARNING;
+               }
+
+               vty_out(vty, "pce-config: %s\n", group_opts->name);
+               pcep_cli_print_pce_config(group_opts, buf, sizeof(buf));
+               vty_out(vty, "%s", buf);
+               return CMD_SUCCESS;
+       }
+
+       /* Show all Peer config groups */
+       for (int i = 0; i < MAX_PCE; i++) {
+               group_opts = pcep_g->config_group_opts[i];
+               if (group_opts == NULL) {
+                       continue;
+               }
+
+               vty_out(vty, "pce-config: %s\n", group_opts->name);
+               pcep_cli_print_pce_config(group_opts, buf, sizeof(buf));
+               vty_out(vty, "%s", buf);
+               buf[0] = 0;
+       }
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pce(struct vty *vty, const char *pce_peer_name)
+{
+       /* If it already exists, it will be updated in the sub-commands */
+       struct pce_opts_cli *pce_opts_cli = pcep_cli_find_pce(pce_peer_name);
+       if (pce_opts_cli == NULL) {
+               pce_opts_cli = pcep_cli_create_pce_opts(pce_peer_name);
+
+               if (!pcep_cli_add_pce(pce_opts_cli)) {
+                       vty_out(vty,
+                               "%% Cannot create PCE, as the Maximum limit of %d PCEs has been reached.\n",
+                               MAX_PCE);
+                       XFREE(MTYPE_PCEP, pce_opts_cli);
+                       return CMD_WARNING;
+               }
+       }
+
+       current_pce_opts_g = pce_opts_cli;
+       vty->node = PCEP_PCE_NODE;
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pce_delete(struct vty *vty, const char *pce_peer_name)
+{
+       struct pce_opts_cli *pce_opts_cli = pcep_cli_find_pce(pce_peer_name);
+       if (pce_opts_cli == NULL) {
+               vty_out(vty, "%% PCC peer does not exist.\n");
+               return CMD_WARNING;
+       }
+
+       /* To better work with frr-reload, go ahead and delete it if its in use
+        */
+       if (pcep_cli_pcc_has_pce(pce_peer_name)) {
+               vty_out(vty,
+                       "%% Notice: the pce is in use by a PCC, also disconnecting.\n");
+               path_pcep_cli_pcc_pcc_peer_delete(vty, pce_peer_name, NULL, 0);
+       }
+
+       pcep_cli_delete_pce(pce_peer_name);
+
+       return CMD_SUCCESS;
+}
+
+/* Internal Util func to show an individual PCE,
+ * only used by path_pcep_cli_show_srte_pcep_pce() */
+static void show_pce_peer(struct vty *vty, struct pce_opts_cli *pce_opts_cli)
+{
+       struct pce_opts *pce_opts = &pce_opts_cli->pce_opts;
+       vty_out(vty, "PCE: %s\n", pce_opts->pce_name);
+
+       /* Remote PCE IP address */
+       if (IS_IPADDR_V6(&pce_opts->addr)) {
+               vty_out(vty, "  %s %s %pI6 %s %d\n", PCEP_VTYSH_ARG_ADDRESS,
+                       PCEP_VTYSH_ARG_IPV6, &pce_opts->addr.ipaddr_v6,
+                       PCEP_VTYSH_ARG_PORT, pce_opts->port);
+       } else {
+               vty_out(vty, "  %s %s %pI4 %s %d\n", PCEP_VTYSH_ARG_ADDRESS,
+                       PCEP_VTYSH_ARG_IP, &pce_opts->addr.ipaddr_v4,
+                       PCEP_VTYSH_ARG_PORT, pce_opts->port);
+       }
+
+       if (pce_opts_cli->config_group_name[0] != '\0') {
+               vty_out(vty, "  pce-config: %s\n",
+                       pce_opts_cli->config_group_name);
+       }
+
+       char buf[1024] = "";
+       pcep_cli_print_pce_config(&pce_opts->config_opts, buf, sizeof(buf));
+       vty_out(vty, "%s", buf);
+}
+
+static int path_pcep_cli_show_srte_pcep_pce(struct vty *vty,
+                                           const char *pce_peer)
+{
+       /* Only show 1 PCE */
+       struct pce_opts_cli *pce_opts_cli;
+       if (pce_peer != NULL) {
+               pce_opts_cli = pcep_cli_find_pce(pce_peer);
+               if (pce_opts_cli == NULL) {
+                       vty_out(vty, "%% PCE [%s] does not exist.\n", pce_peer);
+                       return CMD_WARNING;
+               }
+
+               pcep_cli_merge_pcep_pce_config_options(pce_opts_cli);
+               show_pce_peer(vty, pce_opts_cli);
+
+               return CMD_SUCCESS;
+       }
+
+       /* Show all PCEs */
+       for (int i = 0; i < MAX_PCE; i++) {
+               pce_opts_cli = pcep_g->pce_opts_cli[i];
+               if (pce_opts_cli == NULL) {
+                       continue;
+               }
+
+               pcep_cli_merge_pcep_pce_config_options(pce_opts_cli);
+               show_pce_peer(vty, pce_opts_cli);
+       }
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_peer_sr_draft07(struct vty *vty)
+{
+       struct pcep_config_group_opts *pce_config = NULL;
+
+       if (vty->node == PCEP_PCE_NODE) {
+               /* TODO need to see if the pce is in use, and reset the
+                * connection */
+               pce_config = &current_pce_opts_g->pce_config_group_opts;
+               current_pce_opts_g->merged = false;
+       } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
+               pce_config = current_pcep_config_group_opts_g;
+       } else {
+               return CMD_ERR_NO_MATCH;
+       }
+
+       pce_config->draft07 = true;
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_peer_pce_initiated(struct vty *vty)
+{
+       struct pcep_config_group_opts *pce_config = NULL;
+
+       if (vty->node == PCEP_PCE_NODE) {
+               /* TODO need to see if the pce is in use, and reset the
+                * connection */
+               pce_config = &current_pce_opts_g->pce_config_group_opts;
+               current_pce_opts_g->merged = false;
+       } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
+               pce_config = current_pcep_config_group_opts_g;
+       } else {
+               return CMD_ERR_NO_MATCH;
+       }
+
+       pce_config->pce_initiated = true;
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_peer_tcp_md5_auth(struct vty *vty,
+                                          const char *tcp_md5_auth)
+{
+       struct pcep_config_group_opts *pce_config = NULL;
+
+       if (vty->node == PCEP_PCE_NODE) {
+               /* TODO need to see if the pce is in use, and reset the
+                * connection */
+               pce_config = &current_pce_opts_g->pce_config_group_opts;
+               current_pce_opts_g->merged = false;
+       } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
+               pce_config = current_pcep_config_group_opts_g;
+       } else {
+               return CMD_ERR_NO_MATCH;
+       }
+
+       strncpy(pce_config->tcp_md5_auth, tcp_md5_auth, TCP_MD5SIG_MAXKEYLEN);
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_peer_address(struct vty *vty, const char *ip_str,
+                                     struct in_addr *ip, const char *ipv6_str,
+                                     struct in6_addr *ipv6,
+                                     const char *port_str, long port)
+{
+       struct pce_opts *pce_opts = NULL;
+       if (vty->node == PCEP_PCE_NODE) {
+               /* TODO need to see if the pce is in use, and reset the
+                * connection */
+               pce_opts = &current_pce_opts_g->pce_opts;
+               current_pce_opts_g->merged = false;
+       } else {
+               return CMD_ERR_NO_MATCH;
+       }
+
+       if (ipv6_str != NULL) {
+               pce_opts->addr.ipa_type = IPADDR_V6;
+               memcpy(&pce_opts->addr.ipaddr_v6, ipv6,
+                      sizeof(struct in6_addr));
+       } else if (ip_str != NULL) {
+               pce_opts->addr.ipa_type = IPADDR_V4;
+               memcpy(&pce_opts->addr.ipaddr_v4, ip, sizeof(struct in_addr));
+       } else {
+               return CMD_ERR_NO_MATCH;
+       }
+
+       /* Handle the optional port */
+       pce_opts->port = PCEP_DEFAULT_PORT;
+       PCEP_VTYSH_INT_ARG_CHECK(port_str, port, pce_opts->port, 0, 65535);
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_peer_source_address(struct vty *vty,
+                                            const char *ip_str,
+                                            struct in_addr *ip,
+                                            const char *ipv6_str,
+                                            struct in6_addr *ipv6,
+                                            const char *port_str, long port)
+{
+       struct pcep_config_group_opts *pce_config = NULL;
+       if (vty->node == PCEP_PCE_NODE) {
+               /* TODO need to see if the pce is in use, and reset the
+                * connection */
+               pce_config = &current_pce_opts_g->pce_config_group_opts;
+               current_pce_opts_g->merged = false;
+       } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
+               pce_config = current_pcep_config_group_opts_g;
+       } else {
+               return CMD_ERR_NO_MATCH;
+       }
+
+       /* Handle the optional source IP */
+       if (ipv6_str != NULL) {
+               pce_config->source_ip.ipa_type = IPADDR_V6;
+               memcpy(&pce_config->source_ip.ipaddr_v6, ipv6,
+                      sizeof(struct in6_addr));
+       } else if (ip_str != NULL) {
+               pce_config->source_ip.ipa_type = IPADDR_V4;
+               memcpy(&pce_config->source_ip.ipaddr_v4, ip,
+                      sizeof(struct in_addr));
+       }
+
+       /* Handle the optional port */
+       PCEP_VTYSH_INT_ARG_CHECK(port_str, port, pce_config->source_port, 0,
+                                65535);
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_peer_pcep_pce_config_ref(struct vty *vty,
+                                                 const char *config_group_name)
+{
+       if (vty->node == PCEP_PCE_NODE) {
+               /* TODO need to see if the pce is in use, and reset the
+                * connection */
+               current_pce_opts_g->merged = false;
+       } else {
+               return CMD_ERR_NO_MATCH;
+       }
+
+       struct pcep_config_group_opts *pce_config =
+               pcep_cli_find_pcep_pce_config(config_group_name);
+       if (pce_config == NULL) {
+               vty_out(vty, "%% pce-config [%s] does not exist.\n",
+                       config_group_name);
+               return CMD_WARNING;
+       }
+
+       strlcpy(current_pce_opts_g->config_group_name, config_group_name,
+               sizeof(current_pce_opts_g->config_group_name));
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_peer_timers(
+       struct vty *vty, const char *keep_alive_str, long keep_alive,
+       const char *min_peer_keep_alive_str, long min_peer_keep_alive,
+       const char *max_peer_keep_alive_str, long max_peer_keep_alive,
+       const char *dead_timer_str, long dead_timer,
+       const char *min_peer_dead_timer_str, long min_peer_dead_timer,
+       const char *max_peer_dead_timer_str, long max_peer_dead_timer,
+       const char *pcep_request_str, long pcep_request,
+       const char *session_timeout_interval_str, long session_timeout_interval,
+       const char *delegation_timeout_str, long delegation_timeout)
+{
+       struct pcep_config_group_opts *pce_config = NULL;
+       if (vty->node == PCEP_PCE_NODE) {
+               /* TODO need to see if the pce is in use, and reset the
+                * connection */
+               pce_config = &current_pce_opts_g->pce_config_group_opts;
+               current_pce_opts_g->merged = false;
+       } else if (vty->node == PCEP_PCE_CONFIG_NODE) {
+               pce_config = current_pcep_config_group_opts_g;
+       } else {
+               return CMD_ERR_NO_MATCH;
+       }
+
+       if (min_peer_keep_alive && max_peer_keep_alive)
+               if (min_peer_keep_alive >= max_peer_keep_alive) {
+                       return CMD_ERR_NO_MATCH;
+               }
+
+       if (min_peer_dead_timer && max_peer_dead_timer)
+               if (min_peer_dead_timer >= max_peer_dead_timer) {
+                       return CMD_ERR_NO_MATCH;
+               }
+
+       /* Handle the arguments */
+       PCEP_VTYSH_INT_ARG_CHECK(keep_alive_str, keep_alive,
+                                pce_config->keep_alive_seconds, 0, 64);
+       PCEP_VTYSH_INT_ARG_CHECK(min_peer_keep_alive_str, min_peer_keep_alive,
+                                pce_config->min_keep_alive_seconds, 0, 256);
+       PCEP_VTYSH_INT_ARG_CHECK(max_peer_keep_alive_str, max_peer_keep_alive,
+                                pce_config->max_keep_alive_seconds, 0, 256);
+       PCEP_VTYSH_INT_ARG_CHECK(dead_timer_str, dead_timer,
+                                pce_config->dead_timer_seconds, 3, 256);
+       PCEP_VTYSH_INT_ARG_CHECK(min_peer_dead_timer_str, min_peer_dead_timer,
+                                pce_config->min_dead_timer_seconds, 3, 256);
+       PCEP_VTYSH_INT_ARG_CHECK(max_peer_dead_timer_str, max_peer_dead_timer,
+                                pce_config->max_dead_timer_seconds, 3, 256);
+       PCEP_VTYSH_INT_ARG_CHECK(pcep_request_str, pcep_request,
+                                pce_config->pcep_request_time_seconds, 0, 121);
+       PCEP_VTYSH_INT_ARG_CHECK(
+               session_timeout_interval_str, session_timeout_interval,
+               pce_config->session_timeout_inteval_seconds, 0, 121);
+       PCEP_VTYSH_INT_ARG_CHECK(delegation_timeout_str, delegation_timeout,
+                                pce_config->delegation_timeout_seconds, 0, 61);
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pcc(struct vty *vty)
+{
+       VTY_PUSH_CONTEXT_NULL(PCEP_PCC_NODE);
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pcc_delete(struct vty *vty)
+{
+       /* Clear the pce_connections */
+       memset(&pce_connections_g, 0, sizeof(pce_connections_g));
+       pcc_msd_configured_g = false;
+
+       pcep_ctrl_remove_pcc(pcep_g->fpt, NULL);
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pcc_pcc_msd(struct vty *vty, const char *msd_str,
+                                    long msd)
+{
+       pcc_msd_configured_g = true;
+       PCEP_VTYSH_INT_ARG_CHECK(msd_str, msd, pcc_msd_g, 0, 33);
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pcc_pcc_peer(struct vty *vty, const char *peer_name,
+                                     const char *precedence_str,
+                                     long precedence)
+{
+       /* Check if the pcc-peer exists */
+       struct pce_opts_cli *pce_opts_cli = pcep_cli_find_pce(peer_name);
+       if (pce_opts_cli == NULL) {
+               vty_out(vty, "%% PCE [%s] does not exist.\n", peer_name);
+               return CMD_WARNING;
+       }
+       struct pce_opts *pce_opts = &pce_opts_cli->pce_opts;
+
+       /* Check if the pcc-peer is duplicated */
+       if (pcep_cli_pcc_has_pce(peer_name)) {
+               vty_out(vty, "%% The peer [%s] has already been configured.\n",
+                       peer_name);
+               return CMD_WARNING;
+       }
+
+       /* Get the optional precedence argument */
+       pce_opts->precedence = DEFAULT_PCE_PRECEDENCE;
+       PCEP_VTYSH_INT_ARG_CHECK(precedence_str, precedence,
+                                pce_opts->precedence, 0, 256);
+
+       /* Finalize the pce_opts config values */
+       pcep_cli_merge_pcep_pce_config_options(pce_opts_cli);
+       pcep_cli_add_pce_connection(&pce_opts_cli->pce_opts);
+
+       /* Verify the PCE has the IP set */
+       struct in6_addr zero_v6_addr;
+       memset(&zero_v6_addr, 0, sizeof(struct in6_addr));
+       if (memcmp(&pce_opts->addr.ip, &zero_v6_addr, IPADDRSZ(&pce_opts->addr))
+           == 0) {
+               vty_out(vty,
+                       "%% The peer [%s] does not have an IP set and cannot be used until it does.\n",
+                       peer_name);
+               return CMD_WARNING;
+       }
+
+       /* Update the pcc_opts with the source ip, port, and msd */
+       struct pcc_opts *pcc_opts_copy =
+               XMALLOC(MTYPE_PCEP, sizeof(struct pcc_opts));
+       memcpy(&pcc_opts_copy->addr,
+              &pce_opts_cli->pce_opts.config_opts.source_ip,
+              sizeof(struct pcc_opts));
+       pcc_opts_copy->msd = pcc_msd_g;
+       pcc_opts_copy->port = pce_opts_cli->pce_opts.config_opts.source_port;
+       if (pcep_ctrl_update_pcc_options(pcep_g->fpt, pcc_opts_copy)) {
+               return CMD_WARNING;
+       }
+
+       /* Send a copy of the pce_opts, this one is only used for the CLI */
+       struct pce_opts *pce_opts_copy =
+               XMALLOC(MTYPE_PCEP, sizeof(struct pce_opts));
+       memcpy(pce_opts_copy, pce_opts, sizeof(struct pce_opts));
+       if (pcep_ctrl_update_pce_options(pcep_g->fpt, pce_opts_copy)) {
+               return CMD_WARNING;
+       }
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_pcc_pcc_peer_delete(struct vty *vty,
+                                            const char *peer_name,
+                                            const char *precedence_str,
+                                            long precedence)
+{
+       /* Check if the pcc-peer is connected to the PCC */
+       if (!pcep_cli_pcc_has_pce(peer_name)) {
+               vty_out(vty,
+                       "%% WARN: The peer [%s] is not connected to the PCC.\n",
+                       peer_name);
+               return CMD_WARNING;
+       }
+
+       struct pce_opts_cli *pce_opts_cli = pcep_cli_find_pce(peer_name);
+       pcep_cli_remove_pce_connection(&pce_opts_cli->pce_opts);
+
+       /* Send a copy of the pce_opts, this one is used for CLI only */
+       struct pce_opts *pce_opts_copy =
+               XMALLOC(MTYPE_PCEP, sizeof(struct pce_opts));
+       memcpy(pce_opts_copy, &pce_opts_cli->pce_opts, sizeof(struct pce_opts));
+       pcep_ctrl_remove_pcc(pcep_g->fpt, pce_opts_copy);
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_show_srte_pcep_pcc(struct vty *vty)
+{
+       vty_out(vty, "pcc msd %d\n", pcc_msd_g);
+
+       return CMD_SUCCESS;
+}
+
+/* Internal util function to print pcep capabilities to a buffer */
+static void print_pcep_capabilities(char *buf, size_t buf_len,
+                                   pcep_configuration *config)
+{
+       if (config->support_stateful_pce_lsp_update) {
+               csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_STATEFUL);
+       }
+       if (config->support_include_db_version) {
+               csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_INCL_DB_VER);
+       }
+       if (config->support_lsp_triggered_resync) {
+               csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_LSP_TRIGGERED);
+       }
+       if (config->support_lsp_delta_sync) {
+               csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_LSP_DELTA);
+       }
+       if (config->support_pce_triggered_initial_sync) {
+               csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_PCE_TRIGGERED);
+       }
+       if (config->support_sr_te_pst) {
+               csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_SR_TE_PST);
+       }
+       if (config->pcc_can_resolve_nai_to_sid) {
+               csnprintfrr(buf, buf_len, "%s", PCEP_CLI_CAP_PCC_RESOLVE_NAI);
+       }
+}
+
+/* Internal util function to print a pcep session */
+static void print_pcep_session(struct vty *vty, struct pce_opts *pce_opts,
+                              struct pcep_pcc_info *pcc_info)
+{
+       char buf[1024];
+       buf[0] = '\0';
+
+       vty_out(vty, "\nPCE %s\n", pce_opts->pce_name);
+
+       /* PCE IP */
+       if (IS_IPADDR_V4(&pce_opts->addr)) {
+               vty_out(vty, " PCE IP %pI4 port %d\n",
+                       &pce_opts->addr.ipaddr_v4, pce_opts->port);
+       } else if (IS_IPADDR_V6(&pce_opts->addr)) {
+               vty_out(vty, " PCE IPv6 %pI6 port %d\n",
+                       &pce_opts->addr.ipaddr_v6, pce_opts->port);
+       }
+
+       /* PCC IP */
+       if (IS_IPADDR_V4(&pcc_info->pcc_addr)) {
+               vty_out(vty, " PCC IP %pI4 port %d\n",
+                       &pcc_info->pcc_addr.ipaddr_v4, pcc_info->pcc_port);
+       } else if (IS_IPADDR_V6(&pcc_info->pcc_addr)) {
+               vty_out(vty, " PCC IPv6 %pI6 port %d\n",
+                       &pcc_info->pcc_addr.ipaddr_v6, pcc_info->pcc_port);
+       }
+       vty_out(vty, " PCC MSD %d\n", pcc_info->msd);
+
+       if (pcc_info->status == PCEP_PCC_OPERATING) {
+               vty_out(vty, " Session Status UP\n");
+       } else {
+               vty_out(vty, " Session Status %s\n",
+                       pcc_status_name(pcc_info->status));
+       }
+
+       if (pcc_info->is_best_multi_pce) {
+               vty_out(vty, " Precedence %d, best candidate\n",
+                       ((pcc_info->precedence > 0) ? pcc_info->precedence
+                                                   : DEFAULT_PCE_PRECEDENCE));
+       } else {
+               vty_out(vty, " Precedence %d\n",
+                       ((pcc_info->precedence > 0) ? pcc_info->precedence
+                                                   : DEFAULT_PCE_PRECEDENCE));
+       }
+       vty_out(vty, " Confidence %s\n",
+               ((pcc_info->previous_best) ? "low"
+                : "normal"));
+
+       /* PCEPlib pcep session values, get a thread safe copy of the counters
+        */
+       pcep_session *session =
+               pcep_ctrl_get_pcep_session(pcep_g->fpt, pcc_info->pcc_id);
+
+       /* Config Options values */
+       struct pcep_config_group_opts *config_opts = &pce_opts->config_opts;
+       if (session != NULL) {
+               vty_out(vty, " Timer: KeepAlive config %d, pce-negotiated %d\n",
+                       config_opts->keep_alive_seconds,
+                       session->pcc_config
+                               .keep_alive_pce_negotiated_timer_seconds);
+               vty_out(vty, " Timer: DeadTimer config %d, pce-negotiated %d\n",
+                       config_opts->dead_timer_seconds,
+                       session->pcc_config.dead_timer_pce_negotiated_seconds);
+       } else {
+               vty_out(vty, " Timer: KeepAlive %d\n",
+                       config_opts->keep_alive_seconds);
+               vty_out(vty, " Timer: DeadTimer %d\n",
+                       config_opts->dead_timer_seconds);
+       }
+       vty_out(vty, " Timer: PcRequest %d\n",
+               config_opts->pcep_request_time_seconds);
+       vty_out(vty, " Timer: SessionTimeout Interval %d\n",
+               config_opts->session_timeout_inteval_seconds);
+       vty_out(vty, " Timer: Delegation Timeout %d\n",
+               config_opts->delegation_timeout_seconds);
+       if (strlen(config_opts->tcp_md5_auth) > 0) {
+               vty_out(vty, " TCP MD5 Auth Str: %s\n",
+                       config_opts->tcp_md5_auth);
+       } else {
+               vty_out(vty, " No TCP MD5 Auth\n");
+       }
+
+       if (config_opts->draft07) {
+               vty_out(vty, " PCE SR Version draft07\n");
+       } else {
+               vty_out(vty, " PCE SR Version draft16 and RFC8408\n");
+       }
+
+       vty_out(vty, " Next PcReq ID %d\n", pcc_info->next_reqid);
+       vty_out(vty, " Next PLSP  ID %d\n", pcc_info->next_plspid);
+
+       if (session != NULL) {
+               if (pcc_info->status == PCEP_PCC_SYNCHRONIZING
+                   || pcc_info->status == PCEP_PCC_OPERATING) {
+                       time_t current_time = time(NULL);
+                       struct tm lt = {0};
+                       /* Just for the timezone */
+                       localtime_r(&current_time, &lt);
+                       gmtime_r(&session->time_connected, &lt);
+                       vty_out(vty,
+                               " Connected for %ld seconds, since %d-%02d-%02d %02d:%02d:%02d UTC\n",
+                               (current_time - session->time_connected),
+                               lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday,
+                               lt.tm_hour, lt.tm_min, lt.tm_sec);
+               }
+
+               /* PCC capabilities */
+               buf[0] = '\0';
+               int index = 0;
+               if (config_opts->pce_initiated) {
+                       index += csnprintfrr(buf, sizeof(buf), "%s",
+                                            PCEP_CLI_CAP_PCC_PCE_INITIATED);
+               } else {
+                       index += csnprintfrr(buf, sizeof(buf), "%s",
+                                            PCEP_CLI_CAP_PCC_INITIATED);
+               }
+               print_pcep_capabilities(buf, sizeof(buf) - index,
+                                       &session->pcc_config);
+               vty_out(vty, " PCC Capabilities:%s\n", buf);
+
+               /* PCE capabilities */
+               buf[0] = '\0';
+               print_pcep_capabilities(buf, sizeof(buf), &session->pce_config);
+               if (buf[0] != '\0') {
+                       vty_out(vty, " PCE Capabilities:%s\n", buf);
+               }
+               XFREE(MTYPE_PCEP, session);
+       } else {
+               vty_out(vty, " Detailed session information not available\n");
+       }
+
+       /* Message Counters, get a thread safe copy of the counters */
+       struct counters_group *group =
+               pcep_ctrl_get_counters(pcep_g->fpt, pcc_info->pcc_id);
+
+       if (group != NULL) {
+               struct counters_subgroup *rx_msgs =
+                       find_subgroup(group, COUNTER_SUBGROUP_ID_RX_MSG);
+               struct counters_subgroup *tx_msgs =
+                       find_subgroup(group, COUNTER_SUBGROUP_ID_TX_MSG);
+
+               if (rx_msgs != NULL && tx_msgs != NULL) {
+                       vty_out(vty, " PCEP Message Statistics\n");
+                       vty_out(vty, " %27s %6s\n", "Sent", "Rcvd");
+                       for (int i = 0; i < rx_msgs->max_counters; i++) {
+                               struct counter *rx_counter =
+                                       rx_msgs->counters[i];
+                               struct counter *tx_counter =
+                                       tx_msgs->counters[i];
+                               if (rx_counter != NULL && tx_counter != NULL) {
+                                       vty_out(vty, " %20s: %5d  %5d\n",
+                                               tx_counter->counter_name,
+                                               tx_counter->counter_value,
+                                               rx_counter->counter_value);
+                               }
+                       }
+                       vty_out(vty, " %20s: %5d  %5d\n", "Total",
+                               subgroup_counters_total(tx_msgs),
+                               subgroup_counters_total(rx_msgs));
+               }
+               pcep_lib_free_counters(group);
+       } else {
+               vty_out(vty, " Counters not available\n");
+       }
+
+       XFREE(MTYPE_PCEP, pcc_info);
+}
+
+static int path_pcep_cli_show_srte_pcep_session(struct vty *vty,
+                                               const char *pcc_peer)
+{
+       struct pce_opts_cli *pce_opts_cli;
+       struct pcep_pcc_info *pcc_info;
+
+       /* Only show 1 PCEP session */
+       if (pcc_peer != NULL) {
+               pce_opts_cli = pcep_cli_find_pce(pcc_peer);
+               if (pce_opts_cli == NULL) {
+                       vty_out(vty, "%% PCE [%s] does not exist.\n", pcc_peer);
+                       return CMD_WARNING;
+               }
+
+               if (!pcep_cli_pcc_has_pce(pcc_peer)) {
+                       vty_out(vty, "%% PCC is not connected to PCE [%s].\n",
+                               pcc_peer);
+                       return CMD_WARNING;
+               }
+
+               pcc_info = pcep_ctrl_get_pcc_info(pcep_g->fpt, pcc_peer);
+               if (pcc_info == NULL) {
+                       vty_out(vty,
+                               "%% Cannot retrieve PCEP session info for PCE [%s]\n",
+                               pcc_peer);
+                       return CMD_WARNING;
+               }
+
+               print_pcep_session(vty, &pce_opts_cli->pce_opts, pcc_info);
+
+               return CMD_SUCCESS;
+       }
+
+       /* Show all PCEP sessions */
+       struct pce_opts *pce_opts;
+       int num_pcep_sessions_conf = 0;
+       int num_pcep_sessions_conn = 0;
+       for (int i = 0; i < MAX_PCC; i++) {
+               pce_opts = pce_connections_g.connections[i];
+               if (pce_opts == NULL) {
+                       continue;
+               }
+
+               pcc_info =
+                       pcep_ctrl_get_pcc_info(pcep_g->fpt, pce_opts->pce_name);
+               if (pcc_info == NULL) {
+                       vty_out(vty,
+                               "%% Cannot retrieve PCEP session info for PCE [%s]\n",
+                               pce_opts->pce_name);
+                       continue;
+               }
+
+               num_pcep_sessions_conn +=
+                       pcc_info->status == PCEP_PCC_OPERATING ? 1 : 0;
+               num_pcep_sessions_conf++;
+               print_pcep_session(vty, pce_opts, pcc_info);
+       }
+
+       vty_out(vty, "PCEP Sessions => Configured %d ; Connected %d\n",
+               num_pcep_sessions_conf, num_pcep_sessions_conn);
+
+       return CMD_SUCCESS;
+}
+
+static int path_pcep_cli_clear_srte_pcep_session(struct vty *vty,
+                                                const char *pcc_peer)
+{
+       struct pce_opts_cli *pce_opts_cli;
+
+       /* Only clear 1 PCEP session */
+       if (pcc_peer != NULL) {
+               pce_opts_cli = pcep_cli_find_pce(pcc_peer);
+               if (pce_opts_cli == NULL) {
+                       vty_out(vty, "%% PCE [%s] does not exist.\n", pcc_peer);
+                       return CMD_WARNING;
+               }
+
+               if (!pcep_cli_pcc_has_pce(pcc_peer)) {
+                       vty_out(vty, "%% PCC is not connected to PCE [%s].\n",
+                               pcc_peer);
+                       return CMD_WARNING;
+               }
+
+               pcep_ctrl_reset_pcc_session(pcep_g->fpt,
+                                           pce_opts_cli->pce_opts.pce_name);
+               vty_out(vty, "PCEP session cleared for peer %s\n", pcc_peer);
+
+               return CMD_SUCCESS;
+       }
+
+       /* Clear all PCEP sessions */
+       struct pce_opts *pce_opts;
+       int num_pcep_sessions = 0;
+       for (int i = 0; i < MAX_PCC; i++) {
+               pce_opts = pce_connections_g.connections[i];
+               if (pce_opts == NULL) {
+                       continue;
+               }
+
+               num_pcep_sessions++;
+               pcep_ctrl_reset_pcc_session(pcep_g->fpt, pce_opts->pce_name);
+               vty_out(vty, "PCEP session cleared for peer %s\n",
+                       pce_opts->pce_name);
+       }
+
+       vty_out(vty, "Cleared [%d] PCEP sessions\n", num_pcep_sessions);
+
+       return CMD_SUCCESS;
+}
+
+/*
+ * Config Write functions
+ */
+
+int pcep_cli_debug_config_write(struct vty *vty)
+{
+       char buff[128] = "";
+
+       if (DEBUG_MODE_CHECK(&pcep_g->dbg, DEBUG_MODE_CONF)) {
+               if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC))
+                       csnprintfrr(buff, sizeof(buff), " %s",
+                                   PCEP_VTYSH_ARG_BASIC);
+               if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PATH))
+                       csnprintfrr(buff, sizeof(buff), " %s",
+                                   PCEP_VTYSH_ARG_PATH);
+               if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEP))
+                       csnprintfrr(buff, sizeof(buff), " %s",
+                                   PCEP_VTYSH_ARG_MESSAGE);
+               if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEPLIB))
+                       csnprintfrr(buff, sizeof(buff), " %s",
+                                   PCEP_VTYSH_ARG_PCEPLIB);
+               vty_out(vty, "debug pathd pcep%s\n", buff);
+               buff[0] = 0;
+               return 1;
+       }
+
+       return 0;
+}
+
+int pcep_cli_debug_set_all(uint32_t flags, bool set)
+{
+       DEBUG_FLAGS_SET(&pcep_g->dbg, flags, set);
+
+       /* If all modes have been turned off, don't preserve options. */
+       if (!DEBUG_MODE_CHECK(&pcep_g->dbg, DEBUG_MODE_ALL))
+               DEBUG_CLEAR(&pcep_g->dbg);
+
+       return 0;
+}
+
+int pcep_cli_pcep_config_write(struct vty *vty)
+{
+       vty_out(vty, "  pcep\n");
+       return 1;
+}
+
+int pcep_cli_pcc_config_write(struct vty *vty)
+{
+       struct pce_opts *pce_opts;
+       char buf[128] = "";
+       int lines = 0;
+
+       /* The MSD, nor any PCE peers have been configured on the PCC */
+       if (!pcc_msd_configured_g && pce_connections_g.num_connections == 0) {
+               return lines;
+       }
+
+       vty_out(vty, "   pcc\n");
+       lines++;
+
+       /* Prepare the MSD, if present */
+       if (pcc_msd_configured_g) {
+               vty_out(vty, "    %s %d\n", PCEP_VTYSH_ARG_MSD, pcc_msd_g);
+               lines++;
+       }
+
+       if (pce_connections_g.num_connections == 0) {
+               return lines;
+       }
+
+       buf[0] = 0;
+       for (int i = 0; i < MAX_PCC; i++) {
+               pce_opts = pce_connections_g.connections[i];
+               if (pce_opts == NULL) {
+                       continue;
+               }
+
+               /* Only show the PCEs configured in the pcc sub-command */
+               if (!pcep_cli_pcc_has_pce(pce_opts->pce_name)) {
+                       continue;
+               }
+
+               csnprintfrr(buf, sizeof(buf), "    peer %s",
+                           pce_opts->pce_name);
+               if (pce_opts->precedence > 0
+                   && pce_opts->precedence != DEFAULT_PCE_PRECEDENCE) {
+                       csnprintfrr(buf, sizeof(buf), " %s %d",
+                                   PCEP_VTYSH_ARG_PRECEDENCE,
+                                   pce_opts->precedence);
+               }
+               vty_out(vty, "%s\n", buf);
+               lines++;
+               buf[0] = 0;
+       }
+
+       return lines;
+}
+
+/* Internal function used by pcep_cli_pce_config_write()
+ * and pcep_cli_pcep_pce_config_write() */
+static int pcep_cli_print_pce_config(struct pcep_config_group_opts *group_opts,
+                                    char *buf, size_t buf_len)
+{
+       int lines = 0;
+
+       if (group_opts->source_ip.ipa_type != IPADDR_NONE
+           || group_opts->source_port != 0) {
+               csnprintfrr(buf, buf_len, "   ");
+               if (IS_IPADDR_V4(&group_opts->source_ip)) {
+                       csnprintfrr(buf, buf_len, " %s %s %pI4",
+                                   PCEP_VTYSH_ARG_SOURCE_ADDRESS,
+                                   PCEP_VTYSH_ARG_IP,
+                                   &group_opts->source_ip.ipaddr_v4);
+               } else if (IS_IPADDR_V6(&group_opts->source_ip)) {
+                       csnprintfrr(buf, buf_len, " %s %s %pI6",
+                                   PCEP_VTYSH_ARG_SOURCE_ADDRESS,
+                                   PCEP_VTYSH_ARG_IPV6,
+                                   &group_opts->source_ip.ipaddr_v6);
+               }
+               if (group_opts->source_port > 0) {
+                       csnprintfrr(buf, buf_len, " %s %d", PCEP_VTYSH_ARG_PORT,
+                                   group_opts->source_port);
+               }
+               csnprintfrr(buf, buf_len, "\n");
+               lines++;
+       }
+       /* Group the keep-alive together for devman */
+       if ((group_opts->keep_alive_seconds > 0)
+           || (group_opts->min_keep_alive_seconds > 0)
+           || (group_opts->max_keep_alive_seconds > 0)) {
+               csnprintfrr(buf, buf_len, "    %s", PCEP_VTYSH_ARG_TIMER);
+
+               if (group_opts->keep_alive_seconds > 0) {
+                       csnprintfrr(buf, buf_len, " %s %d",
+                                   PCEP_VTYSH_ARG_KEEP_ALIVE,
+                                   group_opts->keep_alive_seconds);
+               }
+               if (group_opts->min_keep_alive_seconds > 0) {
+                       csnprintfrr(buf, buf_len, " %s %d",
+                                   PCEP_VTYSH_ARG_KEEP_ALIVE_MIN,
+                                   group_opts->min_keep_alive_seconds);
+               }
+               if (group_opts->max_keep_alive_seconds > 0) {
+                       csnprintfrr(buf, buf_len, " %s %d",
+                                   PCEP_VTYSH_ARG_KEEP_ALIVE_MAX,
+                                   group_opts->max_keep_alive_seconds);
+               }
+               csnprintfrr(buf, buf_len, "\n");
+               lines++;
+       }
+
+       /* Group the dead-timer together for devman */
+       if ((group_opts->dead_timer_seconds > 0)
+           || (group_opts->min_dead_timer_seconds > 0)
+           || (group_opts->max_dead_timer_seconds > 0)) {
+               csnprintfrr(buf, buf_len, "    %s", PCEP_VTYSH_ARG_TIMER);
+
+               if (group_opts->dead_timer_seconds > 0) {
+                       csnprintfrr(buf, buf_len, " %s %d",
+                                   PCEP_VTYSH_ARG_DEAD_TIMER,
+                                   group_opts->dead_timer_seconds);
+               }
+               if (group_opts->min_dead_timer_seconds > 0) {
+                       csnprintfrr(buf, buf_len, " %s %d",
+                                   PCEP_VTYSH_ARG_DEAD_TIMER_MIN,
+                                   group_opts->min_dead_timer_seconds);
+               }
+               if (group_opts->max_dead_timer_seconds > 0) {
+                       csnprintfrr(buf, buf_len, " %s %d",
+                                   PCEP_VTYSH_ARG_DEAD_TIMER_MAX,
+                                   group_opts->max_dead_timer_seconds);
+               }
+               csnprintfrr(buf, buf_len, "\n");
+               lines++;
+       }
+
+       if (group_opts->pcep_request_time_seconds > 0) {
+               csnprintfrr(buf, buf_len, "    %s %s %d\n",
+                           PCEP_VTYSH_ARG_TIMER, PCEP_VTYSH_ARG_PCEP_REQUEST,
+                           group_opts->pcep_request_time_seconds);
+               lines++;
+       }
+       if (group_opts->delegation_timeout_seconds > 0) {
+               csnprintfrr(buf, buf_len, "    %s %s %d\n",
+                           PCEP_VTYSH_ARG_TIMER,
+                           PCEP_VTYSH_ARG_DELEGATION_TIMEOUT,
+                           group_opts->delegation_timeout_seconds);
+               lines++;
+       }
+       if (group_opts->session_timeout_inteval_seconds > 0) {
+               csnprintfrr(buf, buf_len, "    %s %s %d\n",
+                           PCEP_VTYSH_ARG_TIMER,
+                           PCEP_VTYSH_ARG_SESSION_TIMEOUT,
+                           group_opts->session_timeout_inteval_seconds);
+               lines++;
+       }
+       if (group_opts->tcp_md5_auth[0] != '\0') {
+               csnprintfrr(buf, buf_len, "    %s %s\n", PCEP_VTYSH_ARG_TCP_MD5,
+                           group_opts->tcp_md5_auth);
+               lines++;
+       }
+       if (group_opts->draft07) {
+               csnprintfrr(buf, buf_len, "    %s\n",
+                           PCEP_VTYSH_ARG_SR_DRAFT07);
+               lines++;
+       }
+       if (group_opts->pce_initiated) {
+               csnprintfrr(buf, buf_len, "    %s\n", PCEP_VTYSH_ARG_PCE_INIT);
+               lines++;
+       }
+
+       return lines;
+}
+
+int pcep_cli_pce_config_write(struct vty *vty)
+{
+       int lines = 0;
+       char buf[1024] = "";
+
+       for (int i = 0; i < MAX_PCE; i++) {
+               struct pce_opts_cli *pce_opts_cli = pcep_g->pce_opts_cli[i];
+               if (pce_opts_cli == NULL) {
+                       continue;
+               }
+               struct pce_opts *pce_opts = &pce_opts_cli->pce_opts;
+
+               vty_out(vty, "   pce %s\n", pce_opts->pce_name);
+               if (IS_IPADDR_V6(&pce_opts->addr)) {
+                       vty_out(vty, "  %s %s %pI6", PCEP_VTYSH_ARG_ADDRESS,
+                               PCEP_VTYSH_ARG_IPV6, &pce_opts->addr.ipaddr_v6);
+               } else if (IS_IPADDR_V4(&pce_opts->addr)) {
+                       vty_out(vty, "    address %s %pI4", PCEP_VTYSH_ARG_IP,
+                               &pce_opts->addr.ipaddr_v4);
+               }
+               if (pce_opts->port != PCEP_DEFAULT_PORT) {
+                       vty_out(vty, "    %s %d", PCEP_VTYSH_ARG_PORT,
+                               pce_opts->port);
+               }
+               vty_out(vty, "%s\n", buf);
+               lines += 2;
+
+               if (pce_opts_cli->config_group_name[0] != '\0') {
+                       vty_out(vty, "    config %s\n",
+                               pce_opts_cli->config_group_name);
+                       lines++;
+               }
+
+               /* Only display the values configured on the PCE, not the values
+                * from its optional pce-config-group, nor the default values */
+               lines += pcep_cli_print_pce_config(
+                       &pce_opts_cli->pce_config_group_opts, buf, sizeof(buf));
+
+               vty_out(vty, "%s", buf);
+               buf[0] = '\0';
+       }
+
+       return lines;
+}
+
+int pcep_cli_pcep_pce_config_write(struct vty *vty)
+{
+       int lines = 0;
+       char buf[1024] = "";
+
+       for (int i = 0; i < MAX_PCE; i++) {
+               struct pcep_config_group_opts *group_opts =
+                       pcep_g->config_group_opts[i];
+               if (group_opts == NULL) {
+                       continue;
+               }
+
+               vty_out(vty, "   pce-config %s\n", group_opts->name);
+               lines += 1;
+
+               lines +=
+                       pcep_cli_print_pce_config(group_opts, buf, sizeof(buf));
+               vty_out(vty, "%s", buf);
+               buf[0] = 0;
+       }
+
+       return lines;
+}
+
+/*
+ * VTYSH command syntax definitions
+ * The param names are taken from the path_pcep_cli_clippy.c generated file.
+ */
+
+DEFPY(show_debugging_pathd_pcep,
+      show_debugging_pathd_pcep_cmd,
+      "show debugging pathd-pcep",
+      SHOW_STR
+      "State of each debugging option\n"
+      "pathd pcep module debugging\n")
+{
+       vty_out(vty, "Pathd pcep debugging status:\n");
+
+       if (DEBUG_MODE_CHECK(&pcep_g->dbg, DEBUG_MODE_CONF)) {
+               if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC))
+                       vty_out(vty, "  Pathd pcep %s debugging is on\n",
+                               PCEP_VTYSH_ARG_BASIC);
+               if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PATH))
+                       vty_out(vty, "  Pathd pcep %s debugging is on\n",
+                               PCEP_VTYSH_ARG_PATH);
+               if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEP))
+                       vty_out(vty, "  Pathd pcep %s debugging is on\n",
+                               PCEP_VTYSH_ARG_MESSAGE);
+               if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEPLIB))
+                       vty_out(vty, "  Pathd pcep %s debugging is on\n",
+                               PCEP_VTYSH_ARG_PCEPLIB);
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFPY(pcep_cli_debug,
+      pcep_cli_debug_cmd,
+      "[no] debug pathd pcep [basic]$basic_str [path]$path_str [message]$message_str [pceplib]$pceplib_str",
+      NO_STR DEBUG_STR
+      "pathd debugging\n"
+      "pcep module debugging\n"
+      "module basic debugging\n"
+      "path structures debugging\n"
+      "pcep message debugging\n"
+      "pceplib debugging\n")
+{
+       return path_pcep_cli_debug(vty, no, basic_str, path_str, message_str,
+                                  pceplib_str);
+}
+
+DEFPY(pcep_cli_show_srte_pcep_counters,
+      pcep_cli_show_srte_pcep_counters_cmd,
+      "show sr-te pcep counters",
+      SHOW_STR
+      "SR-TE info\n"
+      "PCEP info\n"
+      "PCEP counters\n")
+{
+       return path_pcep_cli_show_srte_pcep_counters(vty);
+}
+
+DEFPY_NOSH(
+      pcep_cli_pcep,
+      pcep_cli_pcep_cmd,
+      "pcep",
+      "PCEP configuration\n")
+{
+       vty->node = PCEP_NODE;
+       return CMD_SUCCESS;
+}
+
+DEFPY_NOSH(
+      pcep_cli_pcep_pce_config,
+      pcep_cli_pcep_pce_config_cmd,
+      "[no] pce-config WORD$name",
+      NO_STR
+      "Shared configuration\n"
+      "Shared configuration name\n")
+{
+       if (no == NULL)
+               return path_pcep_cli_pcep_pce_config(vty, name);
+       return path_pcep_cli_pcep_pce_config_delete(vty, name);
+}
+
+DEFPY(pcep_cli_show_srte_pcep_pce_config,
+      pcep_cli_show_srte_pcep_pce_config_cmd,
+      "show sr-te pcep pce-config [<default|WORD>$name]",
+      SHOW_STR
+      "SR-TE info\n"
+      "PCEP info\n"
+      "Show shared PCE configuration\n"
+      "Show default hard-coded values\n"
+      "Shared configuration name\n")
+{
+       return path_pcep_cli_show_srte_pcep_pce_config(vty, name);
+}
+
+DEFPY_NOSH(
+      pcep_cli_pce,
+      pcep_cli_pce_cmd,
+      "[no] pce WORD$name",
+      NO_STR
+      "PCE configuration, address sub-config is mandatory\n"
+      "PCE name\n")
+{
+       if (no == NULL)
+               return path_pcep_cli_pce(vty, name);
+       return path_pcep_cli_pce_delete(vty, name);
+}
+
+DEFPY(pcep_cli_show_srte_pcep_pce,
+      pcep_cli_show_srte_pcep_pce_cmd,
+      "show sr-te pcep pce [WORD$name]",
+      SHOW_STR
+      "SR-TE info\n"
+      "PCEP info\n"
+      "Show detailed pce values\n"
+      "pce name\n")
+{
+       return path_pcep_cli_show_srte_pcep_pce(vty, name);
+}
+
+DEFPY(pcep_cli_peer_sr_draft07,
+      pcep_cli_peer_sr_draft07_cmd,
+      "sr-draft07",
+      "Configure PCC to send PCEP Open with SR draft07\n")
+{
+       return path_pcep_cli_peer_sr_draft07(vty);
+}
+
+DEFPY(pcep_cli_peer_pce_initiated,
+      pcep_cli_peer_pce_initiated_cmd,
+      "pce-initiated",
+      "Configure PCC to accept PCE initiated LSPs\n")
+{
+       return path_pcep_cli_peer_pce_initiated(vty);
+}
+
+DEFPY(pcep_cli_peer_tcp_md5_auth,
+      pcep_cli_peer_tcp_md5_auth_cmd,
+      "tcp-md5-auth WORD",
+      "Configure PCC TCP-MD5 RFC2385 Authentication\n"
+      "TCP-MD5 Authentication string\n")
+{
+       return path_pcep_cli_peer_tcp_md5_auth(vty, tcp_md5_auth);
+}
+
+DEFPY(pcep_cli_peer_address,
+      pcep_cli_peer_address_cmd,
+      "address <ip A.B.C.D | ipv6 X:X::X:X> [port (1024-65535)]",
+      "PCE IP Address configuration, mandatory configuration\n"
+      "PCE IPv4 address\n"
+      "Remote PCE server IPv4 address\n"
+      "PCE IPv6 address\n"
+      "Remote PCE server IPv6 address\n"
+      "Remote PCE server port\n"
+      "Remote PCE server port value\n")
+{
+       return path_pcep_cli_peer_address(vty, ip_str, &ip, ipv6_str, &ipv6,
+                                         port_str, port);
+}
+
+DEFPY(pcep_cli_peer_source_address,
+      pcep_cli_peer_source_address_cmd,
+      "source-address [ip A.B.C.D | ipv6 X:X::X:X] [port (1024-65535)]",
+      "PCE source IP Address configuration\n"
+      "PCE source IPv4 address\n"
+      "PCE source IPv4 address value\n"
+      "PCE source IPv6 address\n"
+      "PCE source IPv6 address value\n"
+      "Source PCE server port\n"
+      "Source PCE server port value\n")
+{
+       return path_pcep_cli_peer_source_address(vty, ip_str, &ip, ipv6_str,
+                                                &ipv6, port_str, port);
+}
+
+DEFPY(pcep_cli_peer_pcep_pce_config_ref,
+      pcep_cli_peer_pcep_pce_config_ref_cmd,
+      "config WORD$name",
+      "PCE shared configuration to use\n"
+      "Shared configuration name\n")
+{
+       return path_pcep_cli_peer_pcep_pce_config_ref(vty, name);
+}
+
+DEFPY(pcep_cli_peer_timers,
+      pcep_cli_peer_timers_cmd,
+      "timer [keep-alive (1-63)] [min-peer-keep-alive (1-255)] [max-peer-keep-alive (1-255)] "
+      "[dead-timer (4-255)] [min-peer-dead-timer (4-255)] [max-peer-dead-timer (4-255)] "
+      "[pcep-request (1-120)] [session-timeout-interval (1-120)] [delegation-timeout (1-60)]",
+      "PCE PCEP Session Timers configuration\n"
+      "PCC Keep Alive Timer\n"
+      "PCC Keep Alive Timer value in seconds\n"
+      "Min Acceptable PCE Keep Alive Timer\n"
+      "Min Acceptable PCE Keep Alive Timer value in seconds\n"
+      "Max Acceptable PCE Keep Alive Timer\n"
+      "Max Acceptable PCE Keep Alive Timer value in seconds\n"
+      "PCC Dead Timer\n"
+      "PCC Dead Timer value in seconds\n"
+      "Min Acceptable PCE Dead Timer\n"
+      "Min Acceptable PCE Dead Timer value in seconds\n"
+      "Max Acceptable PCE Dead Timer\n"
+      "Max Acceptable PCE Dead Timer value in seconds\n"
+      "PCC PCEP Request Timer\n"
+      "PCC PCEP Request Timer value in seconds\n"
+      "PCC Session Timeout Interval\n"
+      "PCC Session Timeout Interval value in seconds\n"
+      "Multi-PCE delegation timeout\n"
+      "Multi-PCE delegation timeout value in seconds\n")
+{
+       return path_pcep_cli_peer_timers(
+               vty, keep_alive_str, keep_alive, min_peer_keep_alive_str,
+               min_peer_keep_alive, max_peer_keep_alive_str,
+               max_peer_keep_alive, dead_timer_str, dead_timer,
+               min_peer_dead_timer_str, min_peer_dead_timer,
+               max_peer_dead_timer_str, max_peer_dead_timer, pcep_request_str,
+               pcep_request, session_timeout_interval_str,
+               session_timeout_interval, delegation_timeout_str,
+               delegation_timeout);
+}
+
+DEFPY_NOSH(
+      pcep_cli_pcc,
+      pcep_cli_pcc_cmd,
+      "[no] pcc",
+      NO_STR
+      "PCC configuration\n")
+{
+       if (no != NULL) {
+               return path_pcep_cli_pcc_delete(vty);
+       } else {
+               return path_pcep_cli_pcc(vty);
+       }
+}
+
+DEFPY(pcep_cli_pcc_pcc_msd,
+      pcep_cli_pcc_pcc_msd_cmd,
+      "msd (1-32)",
+      "PCC maximum SID depth \n"
+      "PCC maximum SID depth value\n")
+{
+       return path_pcep_cli_pcc_pcc_msd(vty, msd_str, msd);
+}
+
+DEFPY(pcep_cli_pcc_pcc_peer,
+      pcep_cli_pcc_pcc_peer_cmd,
+      "[no] peer WORD [precedence (1-255)]",
+      NO_STR
+      "PCC PCE peer\n"
+      "PCC PCE name\n"
+      "PCC Multi-PCE precedence\n"
+      "PCE precedence\n")
+{
+       if (no != NULL) {
+               return path_pcep_cli_pcc_pcc_peer_delete(
+                       vty, peer, precedence_str, precedence);
+       } else {
+               return path_pcep_cli_pcc_pcc_peer(vty, peer, precedence_str,
+                                                 precedence);
+       }
+}
+
+DEFPY(pcep_cli_show_srte_pcc,
+      pcep_cli_show_srte_pcc_cmd,
+      "show sr-te pcep pcc",
+      SHOW_STR
+      "SR-TE info\n"
+      "PCEP info\n"
+      "Show current PCC configuration\n")
+{
+       return path_pcep_cli_show_srte_pcep_pcc(vty);
+}
+
+DEFPY(pcep_cli_show_srte_pcep_session,
+      pcep_cli_show_srte_pcep_session_cmd,
+      "show sr-te pcep session [WORD]$pce",
+      SHOW_STR
+      "SR-TE info\n"
+      "PCEP info\n"
+      "Show PCEP Session information\n"
+      "PCE name\n")
+{
+       return path_pcep_cli_show_srte_pcep_session(vty, pce);
+}
+
+DEFPY(pcep_cli_clear_srte_pcep_session,
+      pcep_cli_clear_srte_pcep_session_cmd,
+      "clear sr-te pcep session [WORD]$pce",
+      CLEAR_STR
+      "SR-TE\n"
+      "PCEP\n"
+      "Reset PCEP connection\n"
+      "PCE name\n")
+{
+       return path_pcep_cli_clear_srte_pcep_session(vty, pce);
+}
+
+void pcep_cli_init(void)
+{
+       hook_register(nb_client_debug_config_write,
+                     pcep_cli_debug_config_write);
+       hook_register(nb_client_debug_set_all, pcep_cli_debug_set_all);
+
+       memset(&pce_connections_g, 0, sizeof(pce_connections_g));
+
+       install_node(&pcep_node);
+       install_node(&pcep_pcc_node);
+       install_node(&pcep_pce_node);
+       install_node(&pcep_pce_config_node);
+
+       install_default(PCEP_PCE_CONFIG_NODE);
+       install_default(PCEP_PCE_NODE);
+       install_default(PCEP_PCC_NODE);
+       install_default(PCEP_NODE);
+
+       install_element(SR_TRAFFIC_ENG_NODE, &pcep_cli_pcep_cmd);
+
+       /* PCEP configuration group related configuration commands */
+       install_element(PCEP_NODE, &pcep_cli_pcep_pce_config_cmd);
+       install_element(PCEP_PCE_CONFIG_NODE,
+                       &pcep_cli_peer_source_address_cmd);
+       install_element(PCEP_PCE_CONFIG_NODE, &pcep_cli_peer_timers_cmd);
+       install_element(PCEP_PCE_CONFIG_NODE, &pcep_cli_peer_sr_draft07_cmd);
+       install_element(PCEP_PCE_CONFIG_NODE, &pcep_cli_peer_pce_initiated_cmd);
+       install_element(PCEP_PCE_CONFIG_NODE, &pcep_cli_peer_tcp_md5_auth_cmd);
+
+       /* PCE peer related configuration commands */
+       install_element(PCEP_NODE, &pcep_cli_pce_cmd);
+       install_element(PCEP_PCE_NODE, &pcep_cli_peer_address_cmd);
+       install_element(PCEP_PCE_NODE, &pcep_cli_peer_source_address_cmd);
+       install_element(PCEP_PCE_NODE, &pcep_cli_peer_pcep_pce_config_ref_cmd);
+       install_element(PCEP_PCE_NODE, &pcep_cli_peer_timers_cmd);
+       install_element(PCEP_PCE_NODE, &pcep_cli_peer_sr_draft07_cmd);
+       install_element(PCEP_PCE_NODE, &pcep_cli_peer_pce_initiated_cmd);
+       install_element(PCEP_PCE_NODE, &pcep_cli_peer_tcp_md5_auth_cmd);
+
+       /* PCC related configuration commands */
+       install_element(ENABLE_NODE, &pcep_cli_show_srte_pcc_cmd);
+       install_element(PCEP_NODE, &pcep_cli_pcc_cmd);
+       install_element(PCEP_PCC_NODE, &pcep_cli_pcc_pcc_peer_cmd);
+       install_element(PCEP_PCC_NODE, &pcep_cli_pcc_pcc_msd_cmd);
+
+       /* Top commands */
+       install_element(CONFIG_NODE, &pcep_cli_debug_cmd);
+       install_element(ENABLE_NODE, &pcep_cli_debug_cmd);
+       install_element(ENABLE_NODE, &show_debugging_pathd_pcep_cmd);
+       install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_counters_cmd);
+       install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_pce_config_cmd);
+       install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_pce_cmd);
+       install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_session_cmd);
+       install_element(ENABLE_NODE, &pcep_cli_clear_srte_pcep_session_cmd);
+}
diff --git a/pathd/path_pcep_cli.h b/pathd/path_pcep_cli.h
new file mode 100644 (file)
index 0000000..0b101ab
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 Volta Networks, Inc
+ *                     Brady Johnson
+ *
+ * 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 _PATH_PCEP_CLI_H_
+#define _PATH_PCEP_CLI_H_
+
+
+/* PCEP CLI Functions */
+void pcep_cli_init(void);
+
+#endif // _PATH_PCEP_CLI_H_
diff --git a/pathd/path_pcep_config.c b/pathd/path_pcep_config.c
new file mode 100644 (file)
index 0000000..989223e
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#include <northbound.h>
+#include <yang.h>
+#include <printfrr.h>
+#include <pcep-objects.h>
+#include "pathd/pathd.h"
+#include "pathd/path_pcep.h"
+#include "pathd/path_pcep_config.h"
+#include "pathd/path_pcep_debug.h"
+#include "thread.h"
+
+#define MAX_XPATH 256
+#define MAX_FLOAT_LEN 22
+#define INETADDR4_MAXLEN 16
+#define INETADDR6_MAXLEN 40
+
+
+static void copy_candidate_objfun_info(struct srte_candidate *candidate,
+                                      struct path *path);
+static void copy_candidate_affinity_filters(struct srte_candidate *candidate,
+                                           struct path *path);
+static struct path_hop *
+path_pcep_config_list_path_hops(struct srte_segment_list *segment_list);
+static struct srte_candidate *lookup_candidate(struct lsp_nb_key *key);
+static char *candidate_name(struct srte_candidate *candidate);
+static enum pcep_lsp_operational_status
+status_int_to_ext(enum srte_policy_status status);
+static enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type);
+static enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type);
+
+static int path_pcep_config_lookup_cb(struct thread *t)
+{
+       struct path *path = THREAD_ARG(t);
+       struct srte_candidate *candidate = lookup_candidate(&path->nbkey);
+       struct srte_lsp *lsp;
+
+       if (candidate == NULL)
+               return 0;
+
+       lsp = candidate->lsp;
+
+       if (path->name == NULL)
+               path->name = candidate_name(candidate);
+       if (path->type == SRTE_CANDIDATE_TYPE_UNDEFINED)
+               path->type = candidate->type;
+       if (path->create_origin == SRTE_ORIGIN_UNDEFINED)
+               path->create_origin = candidate->protocol_origin;
+       if ((path->update_origin == SRTE_ORIGIN_UNDEFINED)
+           && (lsp->segment_list != NULL))
+               path->update_origin = lsp->segment_list->protocol_origin;
+
+       return 0;
+}
+
+void path_pcep_config_lookup(struct path *path)
+{
+       /*
+        * Configuration access is strictly done via the main thread
+        */
+       thread_execute(master, path_pcep_config_lookup_cb, path, 0);
+}
+
+struct path *path_pcep_config_get_path(struct lsp_nb_key *key)
+{
+       struct srte_candidate *candidate = lookup_candidate(key);
+       if (candidate == NULL)
+               return NULL;
+       return candidate_to_path(candidate);
+}
+
+void path_pcep_config_list_path(path_list_cb_t cb, void *arg)
+{
+       struct path *path;
+       struct srte_policy *policy;
+       struct srte_candidate *candidate;
+
+       RB_FOREACH (policy, srte_policy_head, &srte_policies) {
+               RB_FOREACH (candidate, srte_candidate_head,
+                           &policy->candidate_paths) {
+                       path = candidate_to_path(candidate);
+                       if (!cb(path, arg))
+                               return;
+               }
+       }
+}
+
+struct path *candidate_to_path(struct srte_candidate *candidate)
+{
+       char *name;
+       struct path *path;
+       struct path_hop *hop = NULL;
+       struct path_metric *metric = NULL;
+       struct srte_policy *policy;
+       struct srte_lsp *lsp;
+       enum pcep_lsp_operational_status status;
+       enum srte_protocol_origin update_origin = 0;
+       char *originator = NULL;
+
+       policy = candidate->policy;
+       lsp = candidate->lsp;
+
+       if (lsp->segment_list != NULL) {
+               hop = path_pcep_config_list_path_hops(lsp->segment_list);
+               update_origin = lsp->segment_list->protocol_origin;
+               originator = XSTRDUP(MTYPE_PCEP, lsp->segment_list->originator);
+       }
+       path = pcep_new_path();
+       name = candidate_name(candidate);
+       if (CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST)) {
+               status = status_int_to_ext(policy->status);
+       } else {
+               status = PCEP_LSP_OPERATIONAL_DOWN;
+       }
+       for (uint32_t i = 0; i < MAX_METRIC_TYPE; i++) {
+               struct path_metric *path_metric;
+               struct srte_metric *srte_metric = &lsp->metrics[i];
+               if (CHECK_FLAG(srte_metric->flags, F_METRIC_IS_DEFINED)) {
+                       path_metric = pcep_new_metric();
+                       path_metric->next = metric;
+                       metric = path_metric;
+                       metric->type = i + 1;
+                       metric->value = srte_metric->value;
+                       metric->enforce = CHECK_FLAG(srte_metric->flags,
+                                                    F_METRIC_IS_REQUIRED);
+                       metric->is_bound = CHECK_FLAG(srte_metric->flags,
+                                                     F_METRIC_IS_BOUND);
+                       metric->is_computed = CHECK_FLAG(srte_metric->flags,
+                                                        F_METRIC_IS_COMPUTED);
+               }
+       }
+       *path = (struct path){
+               .nbkey = (struct lsp_nb_key){.color = policy->color,
+                                            .endpoint = policy->endpoint,
+                                            .preference =
+                                                    candidate->preference},
+               .create_origin = lsp->protocol_origin,
+               .update_origin = update_origin,
+               .originator = originator,
+               .plsp_id = 0,
+               .name = name,
+               .type = candidate->type,
+               .srp_id = 0,
+               .req_id = 0,
+               .binding_sid = policy->binding_sid,
+               .status = status,
+               .do_remove = false,
+               .go_active = false,
+               .was_created = false,
+               .was_removed = false,
+               .is_synching = false,
+               .is_delegated = false,
+               .first_hop = hop,
+               .first_metric = metric};
+
+       path->has_bandwidth = CHECK_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
+       if (path->has_bandwidth) {
+               path->enforce_bandwidth =
+                       CHECK_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
+               path->bandwidth = lsp->bandwidth;
+       } else {
+               path->enforce_bandwidth = true;
+               path->bandwidth = 0;
+       }
+
+       copy_candidate_objfun_info(candidate, path);
+       copy_candidate_affinity_filters(candidate, path);
+
+       return path;
+}
+
+void copy_candidate_objfun_info(struct srte_candidate *candidate,
+                               struct path *path)
+{
+       struct srte_lsp *lsp = candidate->lsp;
+
+       if (lsp != NULL) {
+               if (CHECK_FLAG(lsp->flags, F_CANDIDATE_HAS_OBJFUN)) {
+                       path->has_pce_objfun = true;
+                       path->pce_objfun = lsp->objfun;
+               } else {
+                       path->has_pce_objfun = false;
+                       path->pce_objfun = OBJFUN_UNDEFINED;
+               }
+       }
+       if (CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN)) {
+               path->has_pcc_objfun = true;
+               path->pcc_objfun = candidate->objfun;
+               path->enforce_pcc_objfun = CHECK_FLAG(
+                       candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
+
+       } else {
+               path->has_pcc_objfun = false;
+               path->pcc_objfun = OBJFUN_UNDEFINED;
+               UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
+       }
+}
+
+void copy_candidate_affinity_filters(struct srte_candidate *candidate,
+                                    struct path *path)
+{
+       bool eany = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_EXCLUDE_ANY);
+       bool iany = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_INCLUDE_ANY);
+       bool iall = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_INCLUDE_ALL);
+       path->has_affinity_filters = eany || iany || iall;
+       path->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY - 1] =
+               eany ? candidate->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY
+                                                  - 1]
+                    : 0;
+       path->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY - 1] =
+               iany ? candidate->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY
+                                                  - 1]
+                    : 0;
+       path->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL - 1] =
+               iall ? candidate->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL
+                                                  - 1]
+                    : 0;
+}
+
+struct path_hop *
+path_pcep_config_list_path_hops(struct srte_segment_list *segment_list)
+{
+       struct srte_segment_entry *segment;
+       struct path_hop *hop = NULL, *last_hop = NULL;
+
+       RB_FOREACH_REVERSE (segment, srte_segment_entry_head,
+                           &segment_list->segments) {
+               hop = pcep_new_hop();
+               *hop = (struct path_hop){
+                       .next = last_hop,
+                       .is_loose = false,
+                       .has_sid = true,
+                       .is_mpls = true,
+                       .has_attribs = false,
+                       .sid = {.mpls = {.label = segment->sid_value}},
+                       .has_nai =
+                               segment->nai_type != SRTE_SEGMENT_NAI_TYPE_NONE,
+                       .nai = {.type = pcep_nai_type(segment->nai_type)}};
+               switch (segment->nai_type) {
+               case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
+               case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
+                       memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
+                              sizeof(struct ipaddr));
+                       break;
+               case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
+               case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
+                       memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
+                              sizeof(struct ipaddr));
+                       memcpy(&hop->nai.remote_addr, &segment->nai_remote_addr,
+                              sizeof(struct ipaddr));
+                       break;
+               case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
+                       memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
+                              sizeof(struct ipaddr));
+                       hop->nai.local_iface = segment->nai_local_iface;
+                       memcpy(&hop->nai.remote_addr, &segment->nai_remote_addr,
+                              sizeof(struct ipaddr));
+                       hop->nai.remote_iface = segment->nai_remote_iface;
+                       break;
+               default:
+                       break;
+               }
+               last_hop = hop;
+       }
+       return hop;
+}
+
+int path_pcep_config_update_path(struct path *path)
+{
+       assert(path != NULL);
+       assert(path->nbkey.preference != 0);
+       assert(path->nbkey.endpoint.ipa_type == IPADDR_V4);
+
+       struct path_hop *hop;
+       struct path_metric *metric;
+       int index;
+       char segment_list_name_buff[64 + 1 + 64 + 1 + 11 + 1];
+       char *segment_list_name = NULL;
+       struct srte_candidate *candidate;
+       struct srte_segment_list *segment_list = NULL;
+       struct srte_segment_entry *segment;
+
+       candidate = lookup_candidate(&path->nbkey);
+
+       // if there is no candidate to update we are done
+       if (!candidate)
+               return 0;
+
+       // first clean up old segment list if present
+       if (candidate->lsp->segment_list) {
+               SET_FLAG(candidate->lsp->segment_list->flags,
+                        F_SEGMENT_LIST_DELETED);
+               candidate->lsp->segment_list = NULL;
+       }
+
+       if (path->first_hop != NULL) {
+               snprintf(segment_list_name_buff, sizeof(segment_list_name_buff),
+                        "%s-%u", path->name, path->plsp_id);
+               segment_list_name = segment_list_name_buff;
+
+               segment_list = srte_segment_list_add(segment_list_name);
+               segment_list->protocol_origin = path->update_origin;
+               strlcpy(segment_list->originator, path->originator,
+                       sizeof(segment_list->originator));
+               SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
+               SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
+
+               for (hop = path->first_hop, index = 10; hop != NULL;
+                    hop = hop->next, index += 10) {
+                       assert(hop->has_sid);
+                       assert(hop->is_mpls);
+
+                       segment = srte_segment_entry_add(segment_list, index);
+
+                       segment->sid_value = (mpls_label_t)hop->sid.mpls.label;
+                       SET_FLAG(segment->segment_list->flags,
+                                F_SEGMENT_LIST_MODIFIED);
+
+                       if (hop->has_nai)
+                               srte_segment_entry_set_nai(
+                                       segment, srte_nai_type(hop->nai.type),
+                                       &hop->nai.local_addr,
+                                       hop->nai.local_iface,
+                                       &hop->nai.remote_addr,
+                                       hop->nai.remote_iface);
+               }
+       }
+
+       candidate->lsp->segment_list = segment_list;
+       SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
+
+       for (metric = path->first_metric; metric != NULL; metric = metric->next)
+               srte_lsp_set_metric(candidate->lsp, metric->type, metric->value,
+                                   metric->enforce, metric->is_bound,
+                                   metric->is_computed);
+
+       if (path->has_bandwidth)
+               srte_lsp_set_bandwidth(candidate->lsp, path->bandwidth,
+                                      path->enforce_bandwidth);
+
+       if (path->has_pce_objfun) {
+               SET_FLAG(candidate->lsp->flags, F_CANDIDATE_HAS_OBJFUN);
+               candidate->lsp->objfun = path->pce_objfun;
+       }
+
+       srte_apply_changes();
+
+       return 0;
+}
+
+struct srte_candidate *lookup_candidate(struct lsp_nb_key *key)
+{
+       struct srte_policy *policy = NULL;
+       policy = srte_policy_find(key->color, &key->endpoint);
+       if (policy == NULL)
+               return NULL;
+       return srte_candidate_find(policy, key->preference);
+}
+
+char *candidate_name(struct srte_candidate *candidate)
+{
+       return asprintfrr(MTYPE_PCEP, "%s-%s", candidate->policy->name,
+                         candidate->name);
+}
+
+enum pcep_lsp_operational_status
+status_int_to_ext(enum srte_policy_status status)
+{
+       switch (status) {
+       case SRTE_POLICY_STATUS_UP:
+               return PCEP_LSP_OPERATIONAL_ACTIVE;
+       case SRTE_POLICY_STATUS_GOING_UP:
+               return PCEP_LSP_OPERATIONAL_GOING_UP;
+       case SRTE_POLICY_STATUS_GOING_DOWN:
+               return PCEP_LSP_OPERATIONAL_GOING_DOWN;
+       default:
+               return PCEP_LSP_OPERATIONAL_DOWN;
+       }
+}
+
+enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type)
+{
+       switch (type) {
+       case SRTE_SEGMENT_NAI_TYPE_NONE:
+               return PCEP_SR_SUBOBJ_NAI_ABSENT;
+       case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
+               return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
+       case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
+               return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
+       case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
+               return PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY;
+       case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
+               return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY;
+       case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
+               return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY;
+       default:
+               return PCEP_SR_SUBOBJ_NAI_UNKNOWN;
+       }
+}
+
+enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type)
+{
+       switch (type) {
+       case PCEP_SR_SUBOBJ_NAI_ABSENT:
+               return SRTE_SEGMENT_NAI_TYPE_NONE;
+       case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
+               return SRTE_SEGMENT_NAI_TYPE_IPV4_NODE;
+       case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
+               return SRTE_SEGMENT_NAI_TYPE_IPV6_NODE;
+       case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
+               return SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY;
+       case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
+               return SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY;
+       case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
+               return SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY;
+       default:
+               return SRTE_SEGMENT_NAI_TYPE_NONE;
+       }
+}
diff --git a/pathd/path_pcep_config.h b/pathd/path_pcep_config.h
new file mode 100644 (file)
index 0000000..de29ab2
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#ifndef _PATH_PCEP_CONFIG_H_
+#define _PATH_PCEP_CONFIG_H_
+
+#include <stdbool.h>
+#include <debug.h>
+
+#include "pathd/path_pcep.h"
+
+#define PATH_NB_NO_CHANGE 0
+#define PATH_NB_OK 1
+#define PATH_NB_ERR -1
+
+typedef int (*path_list_cb_t)(struct path *path, void *arg);
+
+/* Lookup the candidate path and fill up the missing path attributes like name
+   and type. Used for path generated from PCEP message received from the PCE
+   so they contains more information about the candidate path. If no matching
+   policy or candidate path is found, nothing is changed */
+void path_pcep_config_lookup(struct path *path);
+struct path *path_pcep_config_get_path(struct lsp_nb_key *key);
+void path_pcep_config_list_path(path_list_cb_t cb, void *arg);
+int path_pcep_config_update_path(struct path *path);
+struct path *candidate_to_path(struct srte_candidate *candidate);
+
+
+#endif // _PATH_PCEP_CONFIG_H_
diff --git a/pathd/path_pcep_controller.c b/pathd/path_pcep_controller.c
new file mode 100644 (file)
index 0000000..f4871a4
--- /dev/null
@@ -0,0 +1,1078 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "command.h"
+#include "libfrr.h"
+#include "printfrr.h"
+#include "version.h"
+#include "northbound.h"
+#include "frr_pthread.h"
+#include "jhash.h"
+#include "network.h"
+
+#include "pathd/pathd.h"
+#include "pathd/path_errors.h"
+#include "pathd/path_pcep.h"
+#include "pathd/path_pcep_controller.h"
+#include "pathd/path_pcep_pcc.h"
+#include "pathd/path_pcep_config.h"
+#include "pathd/path_pcep_debug.h"
+
+#define MAX_RECONNECT_DELAY 120
+
+#define min(a, b)                                                              \
+       ({                                                                     \
+               __typeof__(a) _a = (a);                                        \
+               __typeof__(b) _b = (b);                                        \
+               _a <= _b ? _a : _b;                                            \
+       })
+
+
+/* Event handling data structures */
+enum pcep_ctrl_event_type {
+       EV_UPDATE_PCC_OPTS = 1,
+       EV_UPDATE_PCE_OPTS,
+       EV_REMOVE_PCC,
+       EV_PATHD_EVENT,
+       EV_SYNC_PATH,
+       EV_SYNC_DONE,
+       EV_PCEPLIB_EVENT,
+       EV_RESET_PCC_SESSION
+};
+
+struct pcep_ctrl_event_data {
+       struct ctrl_state *ctrl_state;
+       enum pcep_ctrl_event_type type;
+       uint32_t sub_type;
+       int pcc_id;
+       void *payload;
+};
+
+struct pcep_main_event_data {
+       pcep_main_event_handler_t handler;
+       int pcc_id;
+       enum pcep_main_event_type type;
+       void *payload;
+};
+
+/* Synchronous call arguments */
+
+struct get_counters_args {
+       struct ctrl_state *ctrl_state;
+       int pcc_id;
+       struct counters_group *counters;
+};
+
+struct send_report_args {
+       struct ctrl_state *ctrl_state;
+       int pcc_id;
+       struct path *path;
+};
+
+struct get_pcep_session_args {
+       struct ctrl_state *ctrl_state;
+       int pcc_id;
+       pcep_session *pcep_session;
+};
+
+/* Internal Functions Called From Main Thread */
+static int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res);
+
+/* Internal Functions Called From Controller Thread */
+static int pcep_thread_finish_event_handler(struct thread *thread);
+static int pcep_thread_get_counters_callback(struct thread *t);
+static int pcep_thread_send_report_callback(struct thread *t);
+static int pcep_thread_get_pcep_session_callback(struct thread *t);
+static int pcep_thread_get_pcc_info_callback(struct thread *t);
+
+/* Controller Thread Timer Handler */
+static int schedule_thread_timer(struct ctrl_state *ctrl_state, int pcc_id,
+                                enum pcep_ctrl_timer_type timer_type,
+                                enum pcep_ctrl_timeout_type timeout_type,
+                                uint32_t delay, void *payload,
+                                struct thread **thread);
+static int schedule_thread_timer_with_cb(
+       struct ctrl_state *ctrl_state, int pcc_id,
+       enum pcep_ctrl_timer_type timer_type,
+       enum pcep_ctrl_timeout_type timeout_type, uint32_t delay, void *payload,
+       struct thread **thread, pcep_ctrl_thread_callback timer_cb);
+static int pcep_thread_timer_handler(struct thread *thread);
+
+/* Controller Thread Socket read/write Handler */
+static int schedule_thread_socket(struct ctrl_state *ctrl_state, int pcc_id,
+                                 enum pcep_ctrl_socket_type type, bool is_read,
+                                 void *payload, int fd, struct thread **thread,
+                                 pcep_ctrl_thread_callback cb);
+
+/* Controller Thread Event Handler */
+static int send_to_thread(struct ctrl_state *ctrl_state, int pcc_id,
+                         enum pcep_ctrl_event_type type, uint32_t sub_type,
+                         void *payload);
+static int send_to_thread_with_cb(struct ctrl_state *ctrl_state, int pcc_id,
+                                 enum pcep_ctrl_event_type type,
+                                 uint32_t sub_type, void *payload,
+                                 pcep_ctrl_thread_callback event_cb);
+static int pcep_thread_event_handler(struct thread *thread);
+static int pcep_thread_event_update_pcc_options(struct ctrl_state *ctrl_state,
+                                               struct pcc_opts *opts);
+static int pcep_thread_event_update_pce_options(struct ctrl_state *ctrl_state,
+                                               int pcc_id,
+                                               struct pce_opts *opts);
+static int pcep_thread_event_remove_pcc_by_id(struct ctrl_state *ctrl_state,
+                                             int pcc_id);
+static int pcep_thread_event_remove_pcc_all(struct ctrl_state *ctrl_state);
+static int pcep_thread_event_remove_pcc(struct ctrl_state *ctrl_state,
+                                       struct pce_opts *pce_opts);
+static int pcep_thread_event_sync_path(struct ctrl_state *ctrl_state,
+                                      int pcc_id, struct path *path);
+static int pcep_thread_event_sync_done(struct ctrl_state *ctrl_state,
+                                      int pcc_id);
+static int pcep_thread_event_pathd_event(struct ctrl_state *ctrl_state,
+                                        enum pcep_pathd_event_type type,
+                                        struct path *path);
+
+/* Main Thread Event Handler */
+static int send_to_main(struct ctrl_state *ctrl_state, int pcc_id,
+                       enum pcep_main_event_type type, void *payload);
+static int pcep_main_event_handler(struct thread *thread);
+
+/* Helper functions */
+static void set_ctrl_state(struct frr_pthread *fpt,
+                          struct ctrl_state *ctrl_state);
+static struct ctrl_state *get_ctrl_state(struct frr_pthread *fpt);
+int get_next_id(struct ctrl_state *ctrl_state);
+int set_pcc_state(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state);
+void remove_pcc_state(struct ctrl_state *ctrl_state,
+                     struct pcc_state *pcc_state);
+static uint32_t backoff_delay(uint32_t max, uint32_t base, uint32_t attempt);
+static const char *timer_type_name(enum pcep_ctrl_timer_type type);
+static const char *timeout_type_name(enum pcep_ctrl_timeout_type type);
+
+
+/* ------------ API Functions Called from Main Thread ------------ */
+
+int pcep_ctrl_initialize(struct thread_master *main_thread,
+                        struct frr_pthread **fpt,
+                        pcep_main_event_handler_t event_handler)
+{
+       assert(fpt != NULL);
+
+       int ret = 0;
+       struct ctrl_state *ctrl_state;
+       struct frr_pthread_attr attr = {
+               .start = frr_pthread_attr_default.start,
+               .stop = pcep_ctrl_halt_cb,
+       };
+
+       PCEP_DEBUG("Initializing pcep module controller");
+
+       /* Create and start the FRR pthread */
+       *fpt = frr_pthread_new(&attr, "PCEP thread", "pcep_controller");
+       if (*fpt == NULL) {
+               flog_err(EC_PATH_SYSTEM_CALL,
+                        "failed to initialize PCEP thread");
+               return 1;
+       }
+       ret = frr_pthread_run(*fpt, NULL);
+       if (ret < 0) {
+               flog_err(EC_PATH_SYSTEM_CALL, "failed to create PCEP thread");
+               return ret;
+       }
+       frr_pthread_wait_running(*fpt);
+
+       /* Initialize the thread state */
+       ctrl_state = XCALLOC(MTYPE_PCEP, sizeof(*ctrl_state));
+       ctrl_state->main = main_thread;
+       ctrl_state->self = (*fpt)->master;
+       ctrl_state->main_event_handler = event_handler;
+       ctrl_state->pcc_count = 0;
+       ctrl_state->pcc_last_id = 0;
+       ctrl_state->pcc_opts =
+               XCALLOC(MTYPE_PCEP, sizeof(*ctrl_state->pcc_opts));
+       /* Default to no PCC address defined */
+       ctrl_state->pcc_opts->addr.ipa_type = IPADDR_NONE;
+       ctrl_state->pcc_opts->port = PCEP_DEFAULT_PORT;
+
+       /* Keep the state reference for events */
+       set_ctrl_state(*fpt, ctrl_state);
+
+       return ret;
+}
+
+int pcep_ctrl_finalize(struct frr_pthread **fpt)
+{
+       assert(fpt != NULL);
+
+       int ret = 0;
+
+       PCEP_DEBUG("Finalizing pcep module controller");
+
+       if (*fpt != NULL) {
+               frr_pthread_stop(*fpt, NULL);
+               *fpt = NULL;
+       }
+
+       return ret;
+}
+
+int pcep_ctrl_update_pcc_options(struct frr_pthread *fpt, struct pcc_opts *opts)
+{
+       struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
+       return send_to_thread(ctrl_state, 0, EV_UPDATE_PCC_OPTS, 0, opts);
+}
+
+int pcep_ctrl_update_pce_options(struct frr_pthread *fpt, struct pce_opts *opts)
+{
+       struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
+       return send_to_thread(ctrl_state, 0, EV_UPDATE_PCE_OPTS, 0, opts);
+}
+
+int pcep_ctrl_remove_pcc(struct frr_pthread *fpt, struct pce_opts *pce_opts)
+{
+       struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
+       return send_to_thread(ctrl_state, 0, EV_REMOVE_PCC, 0, pce_opts);
+}
+
+int pcep_ctrl_reset_pcc_session(struct frr_pthread *fpt, char *pce_name)
+{
+       struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
+       return send_to_thread(ctrl_state, 0, EV_RESET_PCC_SESSION, 0, pce_name);
+}
+
+int pcep_ctrl_pathd_event(struct frr_pthread *fpt,
+                         enum pcep_pathd_event_type type, struct path *path)
+{
+       struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
+       return send_to_thread(ctrl_state, 0, EV_PATHD_EVENT, type, path);
+}
+
+int pcep_ctrl_sync_path(struct frr_pthread *fpt, int pcc_id, struct path *path)
+{
+       struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
+       return send_to_thread(ctrl_state, pcc_id, EV_SYNC_PATH, 0, path);
+}
+
+int pcep_ctrl_sync_done(struct frr_pthread *fpt, int pcc_id)
+{
+       struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
+       return send_to_thread(ctrl_state, pcc_id, EV_SYNC_DONE, 0, NULL);
+}
+
+struct counters_group *pcep_ctrl_get_counters(struct frr_pthread *fpt,
+                                             int pcc_id)
+{
+       struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
+       struct get_counters_args args = {
+               .ctrl_state = ctrl_state, .pcc_id = pcc_id, .counters = NULL};
+       thread_execute(ctrl_state->self, pcep_thread_get_counters_callback,
+                      &args, 0);
+       return args.counters;
+}
+
+pcep_session *pcep_ctrl_get_pcep_session(struct frr_pthread *fpt, int pcc_id)
+{
+       struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
+       struct get_pcep_session_args args = {.ctrl_state = ctrl_state,
+                                            .pcc_id = pcc_id,
+                                            .pcep_session = NULL};
+       thread_execute(ctrl_state->self, pcep_thread_get_pcep_session_callback,
+                      &args, 0);
+       return args.pcep_session;
+}
+
+struct pcep_pcc_info *pcep_ctrl_get_pcc_info(struct frr_pthread *fpt,
+                                            const char *pce_name)
+{
+       struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
+       struct pcep_pcc_info *args = XCALLOC(MTYPE_PCEP, sizeof(*args));
+       args->ctrl_state = ctrl_state;
+       strncpy(args->pce_name, pce_name, sizeof(args->pce_name));
+       thread_execute(ctrl_state->self, pcep_thread_get_pcc_info_callback,
+                      args, 0);
+
+       return args;
+}
+
+void pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
+                          struct path *path)
+{
+       /* Sends a report stynchronously */
+       struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
+       struct send_report_args args = {
+               .ctrl_state = ctrl_state, .pcc_id = pcc_id, .path = path};
+       thread_execute(ctrl_state->self, pcep_thread_send_report_callback,
+                      &args, 0);
+}
+
+/* ------------ Internal Functions Called from Main Thread ------------ */
+
+int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res)
+{
+       thread_add_event(fpt->master, pcep_thread_finish_event_handler,
+                        (void *)fpt, 0, NULL);
+       pthread_join(fpt->thread, res);
+
+       return 0;
+}
+
+
+/* ------------ API Functions Called From Controller Thread ------------ */
+
+void pcep_thread_start_sync(struct ctrl_state *ctrl_state, int pcc_id)
+{
+       send_to_main(ctrl_state, pcc_id, PCEP_MAIN_EVENT_START_SYNC, NULL);
+}
+
+void pcep_thread_update_path(struct ctrl_state *ctrl_state, int pcc_id,
+                            struct path *path)
+{
+       send_to_main(ctrl_state, pcc_id, PCEP_MAIN_EVENT_UPDATE_CANDIDATE,
+                    path);
+}
+
+void pcep_thread_remove_candidate_path_segments(struct ctrl_state *ctrl_state,
+                                               struct pcc_state *pcc_state)
+{
+       if (!pcc_state)
+               return;
+       /* Will be deleted when the event is handled */
+       char *originator = XSTRDUP(MTYPE_PCEP, pcc_state->originator);
+       PCEP_DEBUG("schedule candidate path segments removal for originator %s",
+                  originator);
+       send_to_main(ctrl_state, pcep_pcc_get_pcc_id(pcc_state),
+                    PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP, originator);
+}
+
+void pcep_thread_schedule_sync_best_pce(struct ctrl_state *ctrl_state,
+                                       int pcc_id, int delay,
+                                       struct thread **thread)
+{
+
+       schedule_thread_timer(ctrl_state, pcc_id, TM_CALCULATE_BEST_PCE,
+                             TO_UNDEFINED, delay, NULL, thread);
+}
+
+void pcep_thread_cancel_timer(struct thread **thread)
+{
+       if (thread == NULL || *thread == NULL) {
+               return;
+       }
+
+       struct pcep_ctrl_timer_data *data = THREAD_ARG(*thread);
+       PCEP_DEBUG("Timer %s / %s canceled", timer_type_name(data->timer_type),
+                  timeout_type_name(data->timeout_type));
+       if (data != NULL) {
+               XFREE(MTYPE_PCEP, data);
+       }
+
+       if ((*thread)->master->owner == pthread_self()) {
+               thread_cancel(thread);
+       } else {
+               thread_cancel_async((*thread)->master, thread, NULL);
+       }
+}
+
+void pcep_thread_schedule_reconnect(struct ctrl_state *ctrl_state, int pcc_id,
+                                   int retry_count, struct thread **thread)
+{
+       uint32_t delay = backoff_delay(MAX_RECONNECT_DELAY, 1, retry_count);
+       PCEP_DEBUG("Schedule RECONNECT_PCC for %us (retry %u)", delay,
+                  retry_count);
+       schedule_thread_timer(ctrl_state, pcc_id, TM_RECONNECT_PCC,
+                             TO_UNDEFINED, delay, NULL, thread);
+}
+
+void pcep_thread_schedule_timeout(struct ctrl_state *ctrl_state, int pcc_id,
+                                 enum pcep_ctrl_timeout_type timeout_type,
+                                 uint32_t delay, void *param,
+                                 struct thread **thread)
+{
+       assert(timeout_type > TO_UNDEFINED);
+       assert(timeout_type < TO_MAX);
+       PCEP_DEBUG("Schedule timeout %s for %us",
+                  timeout_type_name(timeout_type), delay);
+       schedule_thread_timer(ctrl_state, pcc_id, TM_TIMEOUT, timeout_type,
+                             delay, param, thread);
+}
+
+void pcep_thread_schedule_pceplib_timer(struct ctrl_state *ctrl_state,
+                                       int delay, void *payload,
+                                       struct thread **thread,
+                                       pcep_ctrl_thread_callback timer_cb)
+{
+       PCEP_DEBUG("Schedule PCEPLIB_TIMER for %us", delay);
+       schedule_thread_timer_with_cb(ctrl_state, 0, TM_PCEPLIB_TIMER,
+                                     TO_UNDEFINED, delay, payload, thread,
+                                     timer_cb);
+}
+
+void pcep_thread_schedule_session_timeout(struct ctrl_state *ctrl_state,
+                                         int pcc_id, int delay,
+                                         struct thread **thread)
+{
+       PCEP_DEBUG("Schedule session_timeout interval for %us", delay);
+       schedule_thread_timer(ctrl_state, pcc_id, TM_SESSION_TIMEOUT_PCC,
+                             TO_UNDEFINED, delay, NULL, thread);
+}
+
+int pcep_thread_pcc_count(struct ctrl_state *ctrl_state)
+{
+       if (ctrl_state == NULL) {
+               return 0;
+       }
+
+       return ctrl_state->pcc_count;
+}
+
+/* ------------ Internal Functions Called From Controller Thread ------------ */
+
+int pcep_thread_finish_event_handler(struct thread *thread)
+{
+       int i;
+       struct frr_pthread *fpt = THREAD_ARG(thread);
+       struct ctrl_state *ctrl_state = fpt->data;
+
+       assert(ctrl_state != NULL);
+
+       for (i = 0; i < MAX_PCC; i++) {
+               if (ctrl_state->pcc[i]) {
+                       pcep_pcc_finalize(ctrl_state, ctrl_state->pcc[i]);
+                       ctrl_state->pcc[i] = NULL;
+               }
+       }
+
+       XFREE(MTYPE_PCEP, ctrl_state->pcc_opts);
+       XFREE(MTYPE_PCEP, ctrl_state);
+       fpt->data = NULL;
+
+       atomic_store_explicit(&fpt->running, false, memory_order_relaxed);
+       return 0;
+}
+
+int pcep_thread_get_counters_callback(struct thread *t)
+{
+       struct get_counters_args *args = THREAD_ARG(t);
+       assert(args != NULL);
+       struct ctrl_state *ctrl_state = args->ctrl_state;
+       assert(ctrl_state != NULL);
+       struct pcc_state *pcc_state;
+
+       pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id);
+       if (pcc_state) {
+               args->counters = pcep_lib_copy_counters(pcc_state->sess);
+       } else {
+               args->counters = NULL;
+       }
+
+       return 0;
+}
+
+int pcep_thread_send_report_callback(struct thread *t)
+{
+       struct send_report_args *args = THREAD_ARG(t);
+       assert(args != NULL);
+       struct ctrl_state *ctrl_state = args->ctrl_state;
+       assert(ctrl_state != NULL);
+       struct pcc_state *pcc_state;
+
+       if (args->pcc_id == 0) {
+               for (int i = 0; i < MAX_PCC; i++) {
+                       if (ctrl_state->pcc[i]) {
+                               pcep_pcc_send_report(ctrl_state,
+                                                    ctrl_state->pcc[i],
+                                                    args->path);
+                       }
+               }
+       } else {
+               pcc_state =
+                       pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id);
+               pcep_pcc_send_report(ctrl_state, pcc_state, args->path);
+       }
+
+       return 0;
+}
+
+int pcep_thread_get_pcep_session_callback(struct thread *t)
+{
+       struct get_pcep_session_args *args = THREAD_ARG(t);
+       assert(args != NULL);
+       struct ctrl_state *ctrl_state = args->ctrl_state;
+       assert(ctrl_state != NULL);
+       struct pcc_state *pcc_state;
+
+       pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id);
+       if (pcc_state) {
+               args->pcep_session =
+                       pcep_lib_copy_pcep_session(pcc_state->sess);
+       }
+
+       return 0;
+}
+
+int pcep_thread_get_pcc_info_callback(struct thread *t)
+{
+       struct pcep_pcc_info *args = THREAD_ARG(t);
+       assert(args != NULL);
+       struct ctrl_state *ctrl_state = args->ctrl_state;
+       assert(ctrl_state != NULL);
+
+       pcep_pcc_copy_pcc_info(ctrl_state->pcc, args);
+
+       return 0;
+}
+
+/* ------------ Controller Thread Timer Handler ------------ */
+
+int schedule_thread_timer_with_cb(struct ctrl_state *ctrl_state, int pcc_id,
+                                 enum pcep_ctrl_timer_type timer_type,
+                                 enum pcep_ctrl_timeout_type timeout_type,
+                                 uint32_t delay, void *payload,
+                                 struct thread **thread,
+                                 pcep_ctrl_thread_callback timer_cb)
+{
+       assert(thread != NULL);
+
+       struct pcep_ctrl_timer_data *data;
+
+       data = XCALLOC(MTYPE_PCEP, sizeof(*data));
+       data->ctrl_state = ctrl_state;
+       data->timer_type = timer_type;
+       data->timeout_type = timeout_type;
+       data->pcc_id = pcc_id;
+       data->payload = payload;
+
+       thread_add_timer(ctrl_state->self, timer_cb, (void *)data, delay,
+                        thread);
+
+       return 0;
+}
+
+int schedule_thread_timer(struct ctrl_state *ctrl_state, int pcc_id,
+                         enum pcep_ctrl_timer_type timer_type,
+                         enum pcep_ctrl_timeout_type timeout_type,
+                         uint32_t delay, void *payload, struct thread **thread)
+{
+       return schedule_thread_timer_with_cb(ctrl_state, pcc_id, timer_type,
+                                            timeout_type, delay, payload,
+                                            thread, pcep_thread_timer_handler);
+}
+
+int pcep_thread_timer_handler(struct thread *thread)
+{
+       /* data unpacking */
+       struct pcep_ctrl_timer_data *data = THREAD_ARG(thread);
+       assert(data != NULL);
+       struct ctrl_state *ctrl_state = data->ctrl_state;
+       assert(ctrl_state != NULL);
+       enum pcep_ctrl_timer_type timer_type = data->timer_type;
+       enum pcep_ctrl_timeout_type timeout_type = data->timeout_type;
+       int pcc_id = data->pcc_id;
+       void *param = data->payload;
+       XFREE(MTYPE_PCEP, data);
+
+       int ret = 0;
+       struct pcc_state *pcc_state = NULL;
+
+       switch (timer_type) {
+       case TM_RECONNECT_PCC:
+               pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+               if (!pcc_state)
+                       return ret;
+               pcep_pcc_reconnect(ctrl_state, pcc_state);
+               break;
+       case TM_TIMEOUT:
+               pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+               if (!pcc_state)
+                       return ret;
+               pcep_pcc_timeout_handler(ctrl_state, pcc_state, timeout_type,
+                                        param);
+               break;
+       case TM_CALCULATE_BEST_PCE:
+               /* Previous best disconnect so new best should be synced */
+               ret = pcep_pcc_timer_update_best_pce(ctrl_state, pcc_id);
+               break;
+       case TM_SESSION_TIMEOUT_PCC:
+               pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+               pcep_thread_remove_candidate_path_segments(ctrl_state,
+                                                          pcc_state);
+               break;
+       default:
+               flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
+                         "Unknown controller timer triggered: %u", timer_type);
+               break;
+       }
+
+       return ret;
+}
+
+int pcep_thread_pcep_event(struct thread *thread)
+{
+       struct pcep_ctrl_event_data *data = THREAD_ARG(thread);
+       assert(data != NULL);
+       struct ctrl_state *ctrl_state = data->ctrl_state;
+       pcep_event *event = data->payload;
+       XFREE(MTYPE_PCEP, data);
+       int i;
+
+       for (i = 0; i < MAX_PCC; i++) {
+               if (ctrl_state->pcc[i]) {
+                       struct pcc_state *pcc_state = ctrl_state->pcc[i];
+                       if (pcc_state->sess != event->session)
+                               continue;
+                       pcep_pcc_pcep_event_handler(ctrl_state, pcc_state,
+                                                   event);
+                       break;
+               }
+       }
+       destroy_pcep_event(event);
+
+       return 0;
+}
+
+/* ------------ Controller Thread Socket Functions ------------ */
+
+int schedule_thread_socket(struct ctrl_state *ctrl_state, int pcc_id,
+                          enum pcep_ctrl_socket_type type, bool is_read,
+                          void *payload, int fd, struct thread **thread,
+                          pcep_ctrl_thread_callback socket_cb)
+{
+       assert(thread != NULL);
+
+       struct pcep_ctrl_socket_data *data;
+
+       data = XCALLOC(MTYPE_PCEP, sizeof(*data));
+       data->ctrl_state = ctrl_state;
+       data->type = type;
+       data->is_read = is_read;
+       data->fd = fd;
+       data->pcc_id = pcc_id;
+       data->payload = payload;
+
+       if (is_read) {
+               thread_add_read(ctrl_state->self, socket_cb, (void *)data, fd,
+                               thread);
+       } else {
+               thread_add_write(ctrl_state->self, socket_cb, (void *)data, fd,
+                                thread);
+       }
+
+       return 0;
+}
+
+int pcep_thread_socket_write(void *fpt, void **thread, int fd, void *payload,
+                            pcep_ctrl_thread_callback socket_cb)
+{
+       struct ctrl_state *ctrl_state = ((struct frr_pthread *)fpt)->data;
+
+       return schedule_thread_socket(ctrl_state, 0, SOCK_PCEPLIB, false,
+                                     payload, fd, (struct thread **)thread,
+                                     socket_cb);
+}
+
+int pcep_thread_socket_read(void *fpt, void **thread, int fd, void *payload,
+                           pcep_ctrl_thread_callback socket_cb)
+{
+       struct ctrl_state *ctrl_state = ((struct frr_pthread *)fpt)->data;
+
+       return schedule_thread_socket(ctrl_state, 0, SOCK_PCEPLIB, true,
+                                     payload, fd, (struct thread **)thread,
+                                     socket_cb);
+}
+
+int pcep_thread_send_ctrl_event(void *fpt, void *payload,
+                               pcep_ctrl_thread_callback cb)
+{
+       struct ctrl_state *ctrl_state = ((struct frr_pthread *)fpt)->data;
+
+       return send_to_thread_with_cb(ctrl_state, 0, EV_PCEPLIB_EVENT, 0,
+                                     payload, cb);
+}
+
+/* ------------ Controller Thread Event Handler ------------ */
+
+int send_to_thread(struct ctrl_state *ctrl_state, int pcc_id,
+                  enum pcep_ctrl_event_type type, uint32_t sub_type,
+                  void *payload)
+{
+       return send_to_thread_with_cb(ctrl_state, pcc_id, type, sub_type,
+                                     payload, pcep_thread_event_handler);
+}
+
+int send_to_thread_with_cb(struct ctrl_state *ctrl_state, int pcc_id,
+                          enum pcep_ctrl_event_type type, uint32_t sub_type,
+                          void *payload, pcep_ctrl_thread_callback event_cb)
+{
+       struct pcep_ctrl_event_data *data;
+
+       data = XCALLOC(MTYPE_PCEP, sizeof(*data));
+       data->ctrl_state = ctrl_state;
+       data->type = type;
+       data->sub_type = sub_type;
+       data->pcc_id = pcc_id;
+       data->payload = payload;
+
+       thread_add_event(ctrl_state->self, event_cb, (void *)data, 0, NULL);
+
+       return 0;
+}
+
+int pcep_thread_event_handler(struct thread *thread)
+{
+       /* data unpacking */
+       struct pcep_ctrl_event_data *data = THREAD_ARG(thread);
+       assert(data != NULL);
+       struct ctrl_state *ctrl_state = data->ctrl_state;
+       assert(ctrl_state != NULL);
+       enum pcep_ctrl_event_type type = data->type;
+       uint32_t sub_type = data->sub_type;
+       int pcc_id = data->pcc_id;
+       void *payload = data->payload;
+       XFREE(MTYPE_PCEP, data);
+
+       int ret = 0;
+
+       /* Possible sub-type values */
+       enum pcep_pathd_event_type path_event_type = PCEP_PATH_UNDEFINED;
+
+       /* Possible payload values */
+       struct path *path = NULL;
+       struct pcc_opts *pcc_opts = NULL;
+       struct pce_opts *pce_opts = NULL;
+       struct pcc_state *pcc_state = NULL;
+
+       switch (type) {
+       case EV_UPDATE_PCC_OPTS:
+               assert(payload != NULL);
+               pcc_opts = (struct pcc_opts *)payload;
+               ret = pcep_thread_event_update_pcc_options(ctrl_state,
+                                                          pcc_opts);
+               break;
+       case EV_UPDATE_PCE_OPTS:
+               assert(payload != NULL);
+               pce_opts = (struct pce_opts *)payload;
+               ret = pcep_thread_event_update_pce_options(ctrl_state, pcc_id,
+                                                          pce_opts);
+               break;
+       case EV_REMOVE_PCC:
+               pce_opts = (struct pce_opts *)payload;
+               ret = pcep_thread_event_remove_pcc(ctrl_state, pce_opts);
+               if (ret == 0) {
+                       ret = pcep_pcc_multi_pce_remove_pcc(ctrl_state,
+                                                           ctrl_state->pcc);
+               }
+               break;
+       case EV_PATHD_EVENT:
+               assert(payload != NULL);
+               path_event_type = (enum pcep_pathd_event_type)sub_type;
+               path = (struct path *)payload;
+               ret = pcep_thread_event_pathd_event(ctrl_state, path_event_type,
+                                                   path);
+               break;
+       case EV_SYNC_PATH:
+               assert(payload != NULL);
+               path = (struct path *)payload;
+               pcep_pcc_multi_pce_sync_path(ctrl_state, pcc_id,
+                                            ctrl_state->pcc);
+               pcep_thread_event_sync_path(ctrl_state, pcc_id, path);
+               break;
+       case EV_SYNC_DONE:
+               ret = pcep_thread_event_sync_done(ctrl_state, pcc_id);
+               break;
+       case EV_RESET_PCC_SESSION:
+               pcc_state = pcep_pcc_get_pcc_by_name(ctrl_state->pcc,
+                                                    (const char *)payload);
+               if (pcc_state) {
+                       pcep_pcc_disable(ctrl_state, pcc_state);
+                       ret = pcep_pcc_enable(ctrl_state, pcc_state);
+               } else {
+                       flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
+                                 "Cannot reset state for PCE: %s",
+                                 (const char *)payload);
+               }
+               break;
+       default:
+               flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
+                         "Unexpected event received in controller thread: %u",
+                         type);
+               break;
+       }
+
+       return ret;
+}
+
+int pcep_thread_event_update_pcc_options(struct ctrl_state *ctrl_state,
+                                        struct pcc_opts *opts)
+{
+       assert(opts != NULL);
+       if (ctrl_state->pcc_opts != NULL) {
+               XFREE(MTYPE_PCEP, ctrl_state->pcc_opts);
+       }
+       ctrl_state->pcc_opts = opts;
+       return 0;
+}
+
+int pcep_thread_event_update_pce_options(struct ctrl_state *ctrl_state,
+                                        int pcc_id, struct pce_opts *pce_opts)
+{
+       if (!pce_opts || !ctrl_state) {
+               return 0;
+       }
+       struct pcc_state *pcc_state;
+       struct pcc_opts *pcc_opts;
+
+       int current_pcc_id =
+               pcep_pcc_get_pcc_id_by_ip_port(ctrl_state->pcc, pce_opts);
+       if (current_pcc_id) {
+               pcc_state =
+                       pcep_pcc_get_pcc_by_id(ctrl_state->pcc, current_pcc_id);
+       } else {
+               pcc_state = pcep_pcc_initialize(ctrl_state,
+                                               get_next_id(ctrl_state));
+               if (set_pcc_state(ctrl_state, pcc_state)) {
+                       XFREE(MTYPE_PCEP, pcc_state);
+                       return 0;
+               }
+       }
+
+       /* Copy the pcc options to delegate it to the update function */
+       pcc_opts = XCALLOC(MTYPE_PCEP, sizeof(*pcc_opts));
+       memcpy(pcc_opts, ctrl_state->pcc_opts, sizeof(*pcc_opts));
+
+       if (pcep_pcc_update(ctrl_state, pcc_state, pcc_opts, pce_opts)) {
+               flog_err(EC_PATH_PCEP_PCC_CONF_UPDATE,
+                        "failed to update PCC configuration");
+       }
+
+
+       return 0;
+}
+
+int pcep_thread_event_remove_pcc_by_id(struct ctrl_state *ctrl_state,
+                                      int pcc_id)
+{
+       if (pcc_id) {
+               struct pcc_state *pcc_state =
+                       pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+               if (pcc_state) {
+                       remove_pcc_state(ctrl_state, pcc_state);
+                       pcep_pcc_finalize(ctrl_state, pcc_state);
+               }
+       }
+       return 0;
+}
+
+int pcep_thread_event_remove_pcc_all(struct ctrl_state *ctrl_state)
+{
+       assert(ctrl_state != NULL);
+
+       for (int i = 0; i < MAX_PCC; i++) {
+               pcep_thread_event_remove_pcc_by_id(
+                       ctrl_state,
+                       pcep_pcc_get_pcc_id_by_idx(ctrl_state->pcc, i));
+       }
+       return 0;
+}
+
+int pcep_thread_event_remove_pcc(struct ctrl_state *ctrl_state,
+                                struct pce_opts *pce_opts)
+{
+       assert(ctrl_state != NULL);
+
+       if (pce_opts) {
+               int pcc_id = pcep_pcc_get_pcc_id_by_ip_port(ctrl_state->pcc,
+                                                           pce_opts);
+               if (pcc_id) {
+                       pcep_thread_event_remove_pcc_by_id(ctrl_state, pcc_id);
+               } else {
+                       return -1;
+               }
+               XFREE(MTYPE_PCEP, pce_opts);
+       } else {
+               pcep_thread_event_remove_pcc_all(ctrl_state);
+       }
+
+       return 0;
+}
+
+int pcep_thread_event_sync_path(struct ctrl_state *ctrl_state, int pcc_id,
+                               struct path *path)
+{
+       struct pcc_state *pcc_state =
+               pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+       pcep_pcc_sync_path(ctrl_state, pcc_state, path);
+       pcep_free_path(path);
+       return 0;
+}
+
+int pcep_thread_event_sync_done(struct ctrl_state *ctrl_state, int pcc_id)
+{
+       struct pcc_state *pcc_state =
+               pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+       pcep_pcc_sync_done(ctrl_state, pcc_state);
+       return 0;
+}
+
+int pcep_thread_event_pathd_event(struct ctrl_state *ctrl_state,
+                                 enum pcep_pathd_event_type type,
+                                 struct path *path)
+{
+       int i;
+
+       for (i = 0; i < MAX_PCC; i++) {
+               if (ctrl_state->pcc[i]) {
+                       struct pcc_state *pcc_state = ctrl_state->pcc[i];
+                       pcep_pcc_pathd_event_handler(ctrl_state, pcc_state,
+                                                    type, path);
+               }
+       }
+
+       pcep_free_path(path);
+
+       return 0;
+}
+
+
+/* ------------ Main Thread Event Handler ------------ */
+
+int send_to_main(struct ctrl_state *ctrl_state, int pcc_id,
+                enum pcep_main_event_type type, void *payload)
+{
+       struct pcep_main_event_data *data;
+
+       data = XCALLOC(MTYPE_PCEP, sizeof(*data));
+       data->handler = ctrl_state->main_event_handler;
+       data->type = type;
+       data->pcc_id = pcc_id;
+       data->payload = payload;
+
+       thread_add_event(ctrl_state->main, pcep_main_event_handler,
+                        (void *)data, 0, NULL);
+       return 0;
+}
+
+int pcep_main_event_handler(struct thread *thread)
+{
+       /* data unpacking */
+       struct pcep_main_event_data *data = THREAD_ARG(thread);
+       assert(data != NULL);
+       pcep_main_event_handler_t handler = data->handler;
+       enum pcep_main_event_type type = data->type;
+       int pcc_id = data->pcc_id;
+       void *payload = data->payload;
+       XFREE(MTYPE_PCEP, data);
+
+       return handler(type, pcc_id, payload);
+}
+
+
+/* ------------ Helper functions ------------ */
+void set_ctrl_state(struct frr_pthread *fpt, struct ctrl_state *ctrl_state)
+{
+       assert(fpt != NULL);
+       fpt->data = ctrl_state;
+}
+
+struct ctrl_state *get_ctrl_state(struct frr_pthread *fpt)
+{
+       assert(fpt != NULL);
+       assert(fpt->data != NULL);
+
+       struct ctrl_state *ctrl_state;
+       ctrl_state = (struct ctrl_state *)fpt->data;
+       assert(ctrl_state != NULL);
+       return ctrl_state;
+}
+
+int get_next_id(struct ctrl_state *ctrl_state)
+{
+       return ++ctrl_state->pcc_last_id;
+}
+
+int set_pcc_state(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state)
+{
+       assert(ctrl_state != NULL);
+       assert(pcep_pcc_get_pcc_id(pcc_state) != 0);
+
+       int current_pcc_idx = pcep_pcc_get_free_pcc_idx(ctrl_state->pcc);
+       if (current_pcc_idx >= 0) {
+               ctrl_state->pcc[current_pcc_idx] = pcc_state;
+               ctrl_state->pcc_count++;
+               PCEP_DEBUG("added pce pcc_id (%d) idx (%d)",
+                          pcep_pcc_get_pcc_id(pcc_state), current_pcc_idx);
+               return 0;
+       } else {
+               PCEP_DEBUG("Max number of pce ");
+               return 1;
+       }
+}
+
+void remove_pcc_state(struct ctrl_state *ctrl_state,
+                     struct pcc_state *pcc_state)
+{
+       assert(ctrl_state != NULL);
+       assert(pcep_pcc_get_pcc_id(pcc_state) != 0);
+
+       int idx = 0;
+       idx = pcep_pcc_get_pcc_idx_by_id(ctrl_state->pcc,
+                                        pcep_pcc_get_pcc_id(pcc_state));
+       if (idx != -1) {
+               ctrl_state->pcc[idx] = NULL;
+               ctrl_state->pcc_count--;
+               PCEP_DEBUG("removed pce pcc_id (%d)",
+                          pcep_pcc_get_pcc_id(pcc_state));
+       }
+}
+
+uint32_t backoff_delay(uint32_t max, uint32_t base, uint32_t retry_count)
+{
+       uint32_t a = min(max, base * (1 << retry_count));
+       uint64_t r = frr_weak_random(), m = RAND_MAX;
+       uint32_t b = (a / 2) + (r * (a / 2)) / m;
+       return b;
+}
+
+const char *timer_type_name(enum pcep_ctrl_timer_type type)
+{
+       switch (type) {
+       case TM_UNDEFINED:
+               return "UNDEFINED";
+       case TM_RECONNECT_PCC:
+               return "RECONNECT_PCC";
+       case TM_PCEPLIB_TIMER:
+               return "PCEPLIB_TIMER";
+       case TM_TIMEOUT:
+               return "TIMEOUT";
+       default:
+               return "UNKNOWN";
+       }
+};
+
+const char *timeout_type_name(enum pcep_ctrl_timeout_type type)
+{
+       switch (type) {
+       case TO_UNDEFINED:
+               return "UNDEFINED";
+       case TO_COMPUTATION_REQUEST:
+               return "COMPUTATION_REQUEST";
+       default:
+               return "UNKNOWN";
+       }
+}
diff --git a/pathd/path_pcep_controller.h b/pathd/path_pcep_controller.h
new file mode 100644 (file)
index 0000000..f6eaa0c
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#ifndef _PATH_PCEP_CONTROLLER_H_
+#define _PATH_PCEP_CONTROLLER_H_
+
+#include "pathd/path_pcep.h"
+
+
+enum pcep_main_event_type {
+       PCEP_MAIN_EVENT_UNDEFINED = 0,
+       PCEP_MAIN_EVENT_START_SYNC,
+       PCEP_MAIN_EVENT_UPDATE_CANDIDATE,
+       PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP
+};
+
+typedef int (*pcep_main_event_handler_t)(enum pcep_main_event_type type,
+                                        int pcc_id, void *payload);
+
+enum pcep_pathd_event_type {
+       PCEP_PATH_UNDEFINED = 0,
+       PCEP_PATH_CREATED,
+       PCEP_PATH_UPDATED,
+       PCEP_PATH_REMOVED
+};
+
+struct ctrl_state {
+       struct thread_master *main;
+       struct thread_master *self;
+       pcep_main_event_handler_t main_event_handler;
+       struct pcc_opts *pcc_opts;
+       int pcc_count;
+       int pcc_last_id;
+       struct pcc_state *pcc[MAX_PCC];
+};
+
+/* Timer handling data structures */
+
+enum pcep_ctrl_timeout_type { TO_UNDEFINED, TO_COMPUTATION_REQUEST, TO_MAX };
+
+enum pcep_ctrl_timer_type {
+       TM_UNDEFINED,
+       TM_RECONNECT_PCC,
+       TM_PCEPLIB_TIMER,
+       TM_TIMEOUT,
+       TM_CALCULATE_BEST_PCE,
+       TM_SESSION_TIMEOUT_PCC,
+       TM_MAX
+};
+
+struct pcep_ctrl_timer_data {
+       struct ctrl_state *ctrl_state;
+       enum pcep_ctrl_timer_type timer_type;
+       enum pcep_ctrl_timeout_type timeout_type;
+       int pcc_id;
+       void *payload;
+};
+
+/* Socket handling data structures */
+
+enum pcep_ctrl_socket_type { SOCK_PCEPLIB = 1 };
+
+struct pcep_ctrl_socket_data {
+       struct ctrl_state *ctrl_state;
+       enum pcep_ctrl_socket_type type;
+       bool is_read;
+       int fd;
+       int pcc_id;
+       void *payload;
+};
+
+typedef int (*pcep_ctrl_thread_callback)(struct thread *);
+
+/* PCC connection information, populated in a thread-safe
+ * manner with pcep_ctrl_get_pcc_info() */
+struct pcep_pcc_info {
+       struct ctrl_state *ctrl_state; /* will be NULL when returned */
+       char pce_name[64];
+       int pcc_id;
+       struct ipaddr pcc_addr;
+       uint16_t pcc_port;
+       int status;
+       short msd;
+       uint32_t next_reqid;
+       uint32_t next_plspid;
+       bool is_best_multi_pce;
+       bool previous_best;
+       uint8_t precedence;
+};
+
+/* Functions called from the main thread */
+int pcep_ctrl_initialize(struct thread_master *main_thread,
+                        struct frr_pthread **fpt,
+                        pcep_main_event_handler_t event_handler);
+int pcep_ctrl_finalize(struct frr_pthread **fpt);
+int pcep_ctrl_update_pcc_options(struct frr_pthread *fpt,
+                                struct pcc_opts *opts);
+int pcep_ctrl_update_pce_options(struct frr_pthread *fpt,
+                                struct pce_opts *opts);
+int pcep_ctrl_remove_pcc(struct frr_pthread *fpt, struct pce_opts *pce_opts);
+int pcep_ctrl_reset_pcc_session(struct frr_pthread *fpt, char *pce_name);
+int pcep_ctrl_pathd_event(struct frr_pthread *fpt,
+                         enum pcep_pathd_event_type type, struct path *path);
+int pcep_ctrl_sync_path(struct frr_pthread *fpt, int pcc_id, struct path *path);
+int pcep_ctrl_sync_done(struct frr_pthread *fpt, int pcc_id);
+struct counters_group *pcep_ctrl_get_counters(struct frr_pthread *fpt,
+                                             int pcc_id);
+pcep_session *pcep_ctrl_get_pcep_session(struct frr_pthread *fpt, int pcc_id);
+struct pcep_pcc_info *pcep_ctrl_get_pcc_info(struct frr_pthread *fpt,
+                                            const char *pce_name);
+
+/* Synchronously send a report, the caller is responsible to free the path,
+ * If `pcc_id` is `0` the report is sent by all PCCs */
+void pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
+                          struct path *path);
+
+/* Functions called from the controller thread */
+void pcep_thread_start_sync(struct ctrl_state *ctrl_state, int pcc_id);
+void pcep_thread_update_path(struct ctrl_state *ctrl_state, int pcc_id,
+                            struct path *path);
+void pcep_thread_cancel_timer(struct thread **thread);
+void pcep_thread_schedule_reconnect(struct ctrl_state *ctrl_state, int pcc_id,
+                                   int retry_count, struct thread **thread);
+void pcep_thread_schedule_timeout(struct ctrl_state *ctrl_state, int pcc_id,
+                                 enum pcep_ctrl_timeout_type type,
+                                 uint32_t delay, void *param,
+                                 struct thread **thread);
+void pcep_thread_schedule_session_timeout(struct ctrl_state *ctrl_state,
+                                         int pcc_id, int delay,
+                                         struct thread **thread);
+void pcep_thread_remove_candidate_path_segments(struct ctrl_state *ctrl_state,
+                                               struct pcc_state *pcc_state);
+
+void pcep_thread_schedule_sync_best_pce(struct ctrl_state *ctrl_state,
+                                       int pcc_id, int delay,
+                                       struct thread **thread);
+void pcep_thread_schedule_pceplib_timer(struct ctrl_state *ctrl_state,
+                                       int delay, void *payload,
+                                       struct thread **thread,
+                                       pcep_ctrl_thread_callback cb);
+int pcep_thread_socket_read(void *fpt, void **thread, int fd, void *payload,
+                           pcep_ctrl_thread_callback cb);
+int pcep_thread_socket_write(void *fpt, void **thread, int fd, void *payload,
+                            pcep_ctrl_thread_callback cb);
+
+int pcep_thread_send_ctrl_event(void *fpt, void *payload,
+                               pcep_ctrl_thread_callback cb);
+int pcep_thread_pcep_event(struct thread *thread);
+int pcep_thread_pcc_count(struct ctrl_state *ctrl_state);
+
+#endif // _PATH_PCEP_CONTROLLER_H_
diff --git a/pathd/path_pcep_debug.c b/pathd/path_pcep_debug.c
new file mode 100644 (file)
index 0000000..bcaadfe
--- /dev/null
@@ -0,0 +1,1771 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#include <string.h>
+#include <stdbool.h>
+#include <time.h>
+#include <libyang/libyang.h>
+
+#include "printfrr.h"
+#include "ipaddr.h"
+
+#include "pathd/path_pcep_debug.h"
+
+static void _format_pcc_opts(int ps, struct pcc_opts *ops);
+static void _format_pce_opts(int ps, struct pce_opts *ops);
+static void _format_pcc_caps(int ps, struct pcep_caps *caps);
+static void _format_pcc_state(int ps, struct pcc_state *state);
+static void _format_ctrl_state(int ps, struct ctrl_state *state);
+static void _format_path(int ps, struct path *path);
+static void _format_path_hop(int ps, struct path_hop *hop);
+static void _format_path_metric(int ps, struct path_metric *metric);
+static void _format_pcep_event(int ps, pcep_event *event);
+static void _format_pcep_message(int ps, struct pcep_message *msg);
+static void _format_pcep_objects(int ps, double_linked_list *objs);
+static void _format_pcep_object(int ps, struct pcep_object_header *obj);
+static void _format_pcep_object_details(int ps, struct pcep_object_header *obj);
+static void _format_pcep_object_error(int ps, struct pcep_object_error *obj);
+static void _format_pcep_object_open(int ps, struct pcep_object_open *obj);
+static void _format_pcep_object_rp(int ps, struct pcep_object_rp *obj);
+static void _format_pcep_object_srp(int ps, struct pcep_object_srp *obj);
+static void _format_pcep_object_lsp(int psps, struct pcep_object_lsp *obj);
+static void _format_pcep_object_lspa(int psps, struct pcep_object_lspa *obj);
+static void
+_format_pcep_object_ipv4_endpoint(int ps,
+                                 struct pcep_object_endpoints_ipv4 *obj);
+static void _format_pcep_object_metric(int ps, struct pcep_object_metric *obj);
+static void _format_pcep_object_bandwidth(int ps,
+                                         struct pcep_object_bandwidth *obj);
+static void _format_pcep_object_nopath(int ps, struct pcep_object_nopath *obj);
+static void
+_format_pcep_object_objfun(int ps, struct pcep_object_objective_function *obj);
+static void _format_pcep_object_ro(int ps, struct pcep_object_ro *obj);
+static void _format_pcep_object_ro_details(int ps,
+                                          struct pcep_object_ro_subobj *ro);
+static void _format_pcep_object_ro_ipv4(int ps,
+                                       struct pcep_ro_subobj_ipv4 *obj);
+static void _format_pcep_object_ro_sr(int ps, struct pcep_ro_subobj_sr *obj);
+static void _format_pcep_object_tlvs(int ps, struct pcep_object_header *obj);
+static void _format_pcep_object_tlv(int ps,
+                                   struct pcep_object_tlv_header *tlv_header);
+static void
+_format_pcep_object_tlv_details(int ps,
+                               struct pcep_object_tlv_header *tlv_header);
+static void _format_pcep_object_tlv_symbolic_path_name(
+       int ps, struct pcep_object_tlv_symbolic_path_name *tlv);
+static void _format_pcep_object_tlv_stateful_pce_capability(
+       int ps, struct pcep_object_tlv_stateful_pce_capability *tlv);
+static void _format_pcep_object_tlv_sr_pce_capability(
+       int ps, struct pcep_object_tlv_sr_pce_capability *tlv);
+static void _format_pcep_object_tlv_path_setup_type(
+       int ps, struct pcep_object_tlv_path_setup_type *tlv);
+
+const char *pcc_status_name(enum pcc_status status)
+{
+       switch (status) {
+       case PCEP_PCC_INITIALIZED:
+               return "INITIALIZED";
+       case PCEP_PCC_DISCONNECTED:
+               return "DISCONNECTED";
+       case PCEP_PCC_CONNECTING:
+               return "CONNECTING";
+       case PCEP_PCC_SYNCHRONIZING:
+               return "SYNCHRONIZING";
+       case PCEP_PCC_OPERATING:
+               return "OPERATING";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *pcep_event_type_name(pcep_event_type event_type)
+{
+       switch (event_type) {
+       case MESSAGE_RECEIVED:
+               return "MESSAGE_RECEIVED";
+       case PCE_CLOSED_SOCKET:
+               return "PCE_CLOSED_SOCKET";
+       case PCE_SENT_PCEP_CLOSE:
+               return "PCE_SENT_PCEP_CLOSE";
+       case PCE_DEAD_TIMER_EXPIRED:
+               return "PCE_DEAD_TIMER_EXPIRED";
+       case PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED:
+               return "PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED";
+       case PCC_CONNECTED_TO_PCE:
+               return "PCC_CONNECTED_TO_PCE";
+       case PCC_PCEP_SESSION_CLOSED:
+               return "PCC_PCEP_SESSION_CLOSED";
+       case PCC_RCVD_INVALID_OPEN:
+               return "PCC_RCVD_INVALID_OPEN";
+       case PCC_RCVD_MAX_INVALID_MSGS:
+               return "PCC_RCVD_MAX_INVALID_MSGS";
+       case PCC_RCVD_MAX_UNKOWN_MSGS:
+               return "PCC_RCVD_MAX_UNKOWN_MSGS";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *pcep_error_type_name(enum pcep_error_type error_type)
+{
+       switch (error_type) {
+
+       case PCEP_ERRT_SESSION_FAILURE:
+               return "SESSION_FAILURE";
+       case PCEP_ERRT_CAPABILITY_NOT_SUPPORTED:
+               return "CAPABILITY_NOT_SUPPORTED";
+       case PCEP_ERRT_UNKNOW_OBJECT:
+               return "UNKNOW_OBJECT";
+       case PCEP_ERRT_NOT_SUPPORTED_OBJECT:
+               return "NOT_SUPPORTED_OBJECT";
+       case PCEP_ERRT_POLICY_VIOLATION:
+               return "POLICY_VIOLATION";
+       case PCEP_ERRT_MANDATORY_OBJECT_MISSING:
+               return "MANDATORY_OBJECT_MISSING";
+       case PCEP_ERRT_SYNC_PC_REQ_MISSING:
+               return "SYNC_PC_REQ_MISSING";
+       case PCEP_ERRT_UNKNOWN_REQ_REF:
+               return "UNKNOWN_REQ_REF";
+       case PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION:
+               return "ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION";
+       case PCEP_ERRT_RECEPTION_OF_INV_OBJECT:
+               return "RECEPTION_OF_INV_OBJECT";
+       case PCEP_ERRT_UNRECOGNIZED_EXRS_SUBOBJ:
+               return "UNRECOGNIZED_EXRS_SUBOBJ";
+       case PCEP_ERRT_DIFFSERV_AWARE_TE_ERROR:
+               return "DIFFSERV_AWARE_TE_ERROR";
+       case PCEP_ERRT_BRPC_PROC_COMPLETION_ERROR:
+               return "BRPC_PROC_COMPLETION_ERROR";
+       case PCEP_ERRT_UNASSIGNED14:
+               return "UNASSIGNED14";
+       case PCEP_ERRT_GLOBAL_CONCURRENT_ERROR:
+               return "GLOBAL_CONCURRENT_ERROR";
+       case PCEP_ERRT_P2PMP_CAP_ERROR:
+               return "P2PMP_CAP_ERROR";
+       case PCEP_ERRT_P2P_ENDPOINTS_ERROR:
+               return "P2P_ENDPOINTS_ERROR";
+       case PCEP_ERRT_P2P_FRAGMENTATION_ERROR:
+               return "P2P_FRAGMENTATION_ERROR";
+       case PCEP_ERRT_INVALID_OPERATION:
+               return "INVALID_OPERATION";
+       case PCEP_ERRT_LSP_STATE_SYNC_ERROR:
+               return "LSP_STATE_SYNC_ERROR";
+       case PCEP_ERRT_INVALID_TE_PATH_SETUP_TYPE:
+               return "INVALID_TE_PATH_SETUP_TYPE";
+       case PCEP_ERRT_UNASSIGNED22:
+               return "UNASSIGNED22";
+       case PCEP_ERRT_BAD_PARAMETER_VALUE:
+               return "BAD_PARAMETER_VALUE";
+       case PCEP_ERRT_LSP_INSTANTIATE_ERROR:
+               return "LSP_INSTANTIATE_ERROR";
+       case PCEP_ERRT_START_TLS_FAILURE:
+               return "START_TLS_FAILURE";
+       case PCEP_ERRT_ASSOCIATION_ERROR:
+               return "ASSOCIATION_ERROR";
+       case PCEP_ERRT_WSON_RWA_ERROR:
+               return "WSON_RWA_ERROR";
+       case PCEP_ERRT_H_PCE_ERROR:
+               return "H_PCE_ERROR";
+       case PCEP_ERRT_PATH_COMP_FAILURE:
+               return "PATH_COMP_FAILURE";
+       case PCEP_ERRT_UNASSIGNED30:
+               return "UNASSIGNED30";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *pcep_error_value_name(enum pcep_error_type error_type,
+                                 enum pcep_error_value error_value)
+{
+       switch (TUP(error_type, error_value)) {
+
+       case TUP(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED, PCEP_ERRV_UNASSIGNED):
+       case TUP(PCEP_ERRT_SYNC_PC_REQ_MISSING, PCEP_ERRV_UNASSIGNED):
+       case TUP(PCEP_ERRT_UNKNOWN_REQ_REF, PCEP_ERRV_UNASSIGNED):
+       case TUP(PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION,
+                PCEP_ERRV_UNASSIGNED):
+       case TUP(PCEP_ERRT_UNRECOGNIZED_EXRS_SUBOBJ, PCEP_ERRV_UNASSIGNED):
+               return "UNASSIGNED";
+
+       case TUP(PCEP_ERRT_SESSION_FAILURE, PCEP_ERRV_RECVD_INVALID_OPEN_MSG):
+               return "RECVD_INVALID_OPEN_MSG";
+       case TUP(PCEP_ERRT_SESSION_FAILURE, PCEP_ERRV_OPENWAIT_TIMED_OUT):
+               return "OPENWAIT_TIMED_OUT";
+       case TUP(PCEP_ERRT_SESSION_FAILURE,
+                PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NO_NEG):
+               return "UNACCEPTABLE_OPEN_MSG_NO_NEG";
+       case TUP(PCEP_ERRT_SESSION_FAILURE,
+                PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG):
+               return "UNACCEPTABLE_OPEN_MSG_NEG";
+       case TUP(PCEP_ERRT_SESSION_FAILURE,
+                PCEP_ERRV_RECVD_SECOND_OPEN_MSG_UNACCEPTABLE):
+               return "RECVD_SECOND_OPEN_MSG_UNACCEPTABLE";
+       case TUP(PCEP_ERRT_SESSION_FAILURE, PCEP_ERRV_RECVD_PCERR):
+               return "RECVD_PCERR";
+       case TUP(PCEP_ERRT_SESSION_FAILURE, PCEP_ERRV_KEEPALIVEWAIT_TIMED_OUT):
+               return "KEEPALIVEWAIT_TIMED_OUT";
+       case TUP(PCEP_ERRT_SESSION_FAILURE,
+                PCEP_ERRV_PCEP_VERSION_NOT_SUPPORTED):
+               return "PCEP_VERSION_NOT_SUPPORTED";
+
+       case TUP(PCEP_ERRT_UNKNOW_OBJECT, PCEP_ERRV_UNREC_OBJECT_CLASS):
+               return "UNREC_OBJECT_CLASS";
+       case TUP(PCEP_ERRT_UNKNOW_OBJECT, PCEP_ERRV_UNREC_OBJECT_TYPE):
+               return "UNREC_OBJECT_TYPE";
+
+       case TUP(PCEP_ERRT_NOT_SUPPORTED_OBJECT,
+                PCEP_ERRV_NOT_SUPPORTED_OBJECT_CLASS):
+               return "NOT_SUPPORTED_OBJECT_CLASS";
+       case TUP(PCEP_ERRT_NOT_SUPPORTED_OBJECT,
+                PCEP_ERRV_NOT_SUPPORTED_OBJECT_TYPE):
+               return "NOT_SUPPORTED_OBJECT_TYPE";
+       case TUP(PCEP_ERRT_NOT_SUPPORTED_OBJECT, PCEP_ERRV_UNSUPPORTED_PARAM):
+               return "UNSUPPORTED_PARAM";
+       case TUP(PCEP_ERRT_NOT_SUPPORTED_OBJECT,
+                PCEP_ERRV_UNSUPPORTED_NW_PERF_CONSTRAINT):
+               return "UNSUPPORTED_NW_PERF_CONSTRAINT";
+       case TUP(PCEP_ERRT_NOT_SUPPORTED_OBJECT,
+                PCEP_ERRV_NOT_SUPPORTED_BW_OBJECT_3_4):
+               return "NOT_SUPPORTED_BW_OBJECT_3_4";
+       case TUP(PCEP_ERRT_NOT_SUPPORTED_OBJECT,
+                PCEP_ERRV_UNSUPPORTED_ENDPOINT_TYPE):
+               return "UNSUPPORTED_ENDPOINT_TYPE";
+       case TUP(PCEP_ERRT_NOT_SUPPORTED_OBJECT,
+                PCEP_ERRV_UNSUPPORTED_ENDPOINT_TLV):
+               return "UNSUPPORTED_ENDPOINT_TLV";
+       case TUP(PCEP_ERRT_NOT_SUPPORTED_OBJECT,
+                PCEP_ERRV_UNSUPPORTED_RP_FLAG_GRANULARITY):
+               return "UNSUPPORTED_RP_FLAG_GRANULARITY";
+
+       case TUP(PCEP_ERRT_POLICY_VIOLATION,
+                PCEP_ERRV_C_BIT_SET_IN_METRIC_OBJECT):
+               return "C_BIT_SET_IN_METRIC_OBJECT";
+       case TUP(PCEP_ERRT_POLICY_VIOLATION,
+                PCEP_ERRV_O_BIT_CLEARD_IN_RP_OBJECT):
+               return "O_BIT_CLEARD_IN_RP_OBJECT";
+       case TUP(PCEP_ERRT_POLICY_VIOLATION,
+                PCEP_ERRV_OBJECTIVE_FUNC_NOT_ALLOWED):
+               return "OBJECTIVE_FUNC_NOT_ALLOWED";
+       case TUP(PCEP_ERRT_POLICY_VIOLATION, PCEP_ERRV_RP_OF_BIT_SET):
+               return "RP_OF_BIT_SET";
+       case TUP(PCEP_ERRT_POLICY_VIOLATION,
+                PCEP_ERRV_GLOBAL_CONCURRENCY_NOT_ALLOWED):
+               return "GLOBAL_CONCURRENCY_NOT_ALLOWED";
+       case TUP(PCEP_ERRT_POLICY_VIOLATION, PCEP_ERRV_MONITORING_MSG_REJECTED):
+               return "MONITORING_MSG_REJECTED";
+       case TUP(PCEP_ERRT_POLICY_VIOLATION,
+                PCEP_ERRV_P2MP_PATH_COMP_NOT_ALLOWED):
+               return "P2MP_PATH_COMP_NOT_ALLOWED";
+       case TUP(PCEP_ERRT_POLICY_VIOLATION,
+                PCEP_ERRV_UNALLOWED_NW_PERF_CONSTRAINT):
+               return "UNALLOWED_NW_PERF_CONSTRAINT";
+
+       case TUP(PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                PCEP_ERRV_RP_OBJECT_MISSING):
+               return "RP_OBJECT_MISSING";
+       case TUP(PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                PCEP_ERRV_RRO_OBJECT_MISSING_FOR_REOP):
+               return "RRO_OBJECT_MISSING_FOR_REOP";
+       case TUP(PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                PCEP_ERRV_EP_OBJECT_MISSING):
+               return "EP_OBJECT_MISSING";
+       case TUP(PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                PCEP_ERRV_MONITOR_OBJECT_MISSING):
+               return "MONITOR_OBJECT_MISSING";
+       case TUP(PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                PCEP_ERRV_LSP_OBJECT_MISSING):
+               return "LSP_OBJECT_MISSING";
+       case TUP(PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                PCEP_ERRV_ERO_OBJECT_MISSING):
+               return "ERO_OBJECT_MISSING";
+       case TUP(PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                PCEP_ERRV_SRP_OBJECT_MISSING):
+               return "SRP_OBJECT_MISSING";
+       case TUP(PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                PCEP_ERRV_LSP_ID_TLV_MISSING):
+               return "LSP_ID_TLV_MISSING";
+       case TUP(PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                PCEP_ERRV_LSP_DB_TLV_MISSING):
+               return "LSP_DB_TLV_MISSING";
+       case TUP(PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                PCEP_ERRV_S2LS_OBJECT_MISSING):
+               return "S2LS_OBJECT_MISSING";
+       case TUP(PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                PCEP_ERRV_P2MP_LSP_ID_TLV_MISSING):
+               return "P2MP_LSP_ID_TLV_MISSING";
+       case TUP(PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                PCEP_ERRV_DISJOINTED_CONF_TLV_MISSING):
+               return "DISJOINTED_CONF_TLV_MISSING";
+
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_P_FLAG_NOT_CORRECT_IN_OBJECT):
+               return "P_FLAG_NOT_CORRECT_IN_OBJECT";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT, PCEP_ERRV_BAD_LABEL_VALUE):
+               return "BAD_LABEL_VALUE";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_UNSUPPORTED_NUM_SR_ERO_SUBOBJECTS):
+               return "UNSUPPORTED_NUM_SR_ERO_SUBOBJECTS";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT, PCEP_ERRV_BAD_LABEL_FORMAT):
+               return "BAD_LABEL_FORMAT";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT, PCEP_ERRV_ERO_SR_ERO_MIX):
+               return "ERO_SR_ERO_MIX";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_SR_ERO_SID_NAI_ABSENT):
+               return "SR_ERO_SID_NAI_ABSENT";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_SR_RRO_SID_NAI_ABSENT):
+               return "SR_RRO_SID_NAI_ABSENT";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_SYMBOLIC_PATH_NAME_TLV_MISSING):
+               return "SYMBOLIC_PATH_NAME_TLV_MISSING";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_MSD_EXCEEDS_PCEP_SESSION_MAX):
+               return "MSD_EXCEEDS_PCEP_SESSION_MAX";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT, PCEP_ERRV_RRO_SR_RRO_MIX):
+               return "RRO_SR_RRO_MIX";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT, PCEP_ERRV_MALFORMED_OBJECT):
+               return "MALFORMED_OBJECT";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_MISSING_PCE_SR_CAP_TLV):
+               return "MISSING_PCE_SR_CAP_TLV";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT, PCEP_ERRV_UNSUPPORTED_NAI):
+               return "UNSUPPORTED_NAI";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT, PCEP_ERRV_UNKNOWN_SID):
+               return "UNKNOWN_SID";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_CANNOT_RESOLVE_NAI_TO_SID):
+               return "CANNOT_RESOLVE_NAI_TO_SID";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_COULD_NOT_FIND_SRGB):
+               return "COULD_NOT_FIND_SRGB";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT, PCEP_ERRV_SID_EXCEEDS_SRGB):
+               return "SID_EXCEEDS_SRGB";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_COULD_NOT_FIND_SRLB):
+               return "COULD_NOT_FIND_SRLB";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT, PCEP_ERRV_SID_EXCEEDS_SRLB):
+               return "SID_EXCEEDS_SRLB";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT, PCEP_ERRV_INCONSISTENT_SID):
+               return "INCONSISTENT_SID";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_MSD_MUST_BE_NONZERO):
+               return "MSD_MUST_BE_NONZERO";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_MISMATCH_O_S2LS_LSP):
+               return "MISMATCH_O_S2LS_LSP";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_INCOMPATIBLE_H_PCE_OF):
+               return "INCOMPATIBLE_H_PCE_OF";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_BAD_BANDWIDTH_TYPE_3_4):
+               return "BAD_BANDWIDTH_TYPE_3_4";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_UNSUPPORTED_LSP_PROT_FLAGS):
+               return "UNSUPPORTED_LSP_PROT_FLAGS";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_UNSUPPORTED_2ND_LSP_PROT_FLAGS):
+               return "UNSUPPORTED_2ND_LSP_PROT_FLAGS";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_UNSUPPORTED_LINK_PROT_TYPE):
+               return "UNSUPPORTED_LINK_PROT_TYPE";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_LABEL_SET_TLV_NO_RP_R):
+               return "LABEL_SET_TLV_NO_RP_R";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_WRONG_LABEL_SET_TLV_O_L_SET):
+               return "WRONG_LABEL_SET_TLV_O_L_SET";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_WRONG_LABEL_SET_O_SET):
+               return "WRONG_LABEL_SET_O_SET";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_MISSING_GMPLS_CAP_TLV):
+               return "MISSING_GMPLS_CAP_TLV";
+       case TUP(PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                PCEP_ERRV_INCOMPATIBLE_OF_CODE):
+               return "INCOMPATIBLE_OF_CODE";
+
+       case TUP(PCEP_ERRT_DIFFSERV_AWARE_TE_ERROR,
+                PCEP_ERRV_UNSUPPORTED_CLASS_TYPE):
+               return "UNSUPPORTED_CLASS_TYPE";
+       case TUP(PCEP_ERRT_DIFFSERV_AWARE_TE_ERROR,
+                PCEP_ERRV_INVALID_CLASS_TYPE):
+               return "INVALID_CLASS_TYPE";
+       case TUP(PCEP_ERRT_DIFFSERV_AWARE_TE_ERROR,
+                PCEP_ERRV_CLASS_SETUP_TYPE_NOT_TE_CLASS):
+               return "CLASS_SETUP_TYPE_NOT_TE_CLASS";
+
+       case TUP(PCEP_ERRT_BRPC_PROC_COMPLETION_ERROR,
+                PCEP_ERRV_BRPC_PROC_NOT_SUPPORTED):
+               return "BRPC_PROC_NOT_SUPPORTED";
+
+       case TUP(PCEP_ERRT_GLOBAL_CONCURRENT_ERROR,
+                PCEP_ERRV_INSUFFICIENT_MEMORY):
+               return "INSUFFICIENT_MEMORY";
+       case TUP(PCEP_ERRT_GLOBAL_CONCURRENT_ERROR,
+                PCEP_ERRV_GLOBAL_CONCURRENT_OPT_NOT_SUPPORTED):
+               return "GLOBAL_CONCURRENT_OPT_NOT_SUPPORTED";
+
+       case TUP(PCEP_ERRT_P2PMP_CAP_ERROR, PCEP_ERRV_PCE_INSUFFICIENT_MEMORY):
+               return "PCE_INSUFFICIENT_MEMORY";
+       case TUP(PCEP_ERRT_P2PMP_CAP_ERROR,
+                PCEP_ERRV_PCE_NOT_CAPABLE_P2MP_COMP):
+               return "PCE_NOT_CAPABLE_P2MP_COMP";
+
+       case TUP(PCEP_ERRT_P2P_ENDPOINTS_ERROR,
+                PCEP_ERRV_NO_EP_WITH_LEAF_TYPE2):
+               return "NO_EP_WITH_LEAF_TYPE2";
+       case TUP(PCEP_ERRT_P2P_ENDPOINTS_ERROR,
+                PCEP_ERRV_NO_EP_WITH_LEAF_TYPE3):
+               return "NO_EP_WITH_LEAF_TYPE3";
+       case TUP(PCEP_ERRT_P2P_ENDPOINTS_ERROR,
+                PCEP_ERRV_NO_EP_WITH_LEAF_TYPE4):
+               return "NO_EP_WITH_LEAF_TYPE4";
+       case TUP(PCEP_ERRT_P2P_ENDPOINTS_ERROR, PCEP_ERRV_INCONSITENT_EP):
+               return "INCONSITENT_EP";
+
+       case TUP(PCEP_ERRT_P2P_FRAGMENTATION_ERROR,
+                PCEP_ERRV_FRAG_REQUEST_FAILURE):
+               return "FRAG_REQUEST_FAILURE";
+       case TUP(PCEP_ERRT_P2P_FRAGMENTATION_ERROR,
+                PCEP_ERRV_FRAG_REPORT_FAILURE):
+               return "FRAG_REPORT_FAILURE";
+       case TUP(PCEP_ERRT_P2P_FRAGMENTATION_ERROR,
+                PCEP_ERRV_FRAG_UPDATE_FAILURE):
+               return "FRAG_UPDATE_FAILURE";
+       case TUP(PCEP_ERRT_P2P_FRAGMENTATION_ERROR,
+                PCEP_ERRV_FRAG_INSTANTIATION_FAILURE):
+               return "FRAG_INSTANTIATION_FAILURE";
+
+       case TUP(PCEP_ERRT_INVALID_OPERATION,
+                PCEP_ERRV_LSP_UPDATE_FOR_NON_DELEGATED_LSP):
+               return "LSP_UPDATE_FOR_NON_DELEGATED_LS";
+       case TUP(PCEP_ERRT_INVALID_OPERATION,
+                PCEP_ERRV_LSP_UPDATE_NON_ADVERTISED_PCE):
+               return "LSP_UPDATE_NON_ADVERTISED_PC";
+       case TUP(PCEP_ERRT_INVALID_OPERATION,
+                PCEP_ERRV_LSP_UPDATE_UNKNOWN_PLSP_ID):
+               return "LSP_UPDATE_UNKNOWN_PLSP_I";
+       case TUP(PCEP_ERRT_INVALID_OPERATION,
+                PCEP_ERRV_LSP_REPORT_NON_ADVERTISED_PCE):
+               return "LSP_REPORT_NON_ADVERTISED_PC";
+       case TUP(PCEP_ERRT_INVALID_OPERATION,
+                PCEP_ERRV_PCE_INIT_LSP_LIMIT_REACHED):
+               return "PCE_INIT_LSP_LIMIT_REACHE";
+       case TUP(PCEP_ERRT_INVALID_OPERATION,
+                PCEP_ERRV_PCE_INIT_LSP_DELEGATION_CANT_REVOKE):
+               return "PCE_INIT_LSP_DELEGATION_CANT_REVOK";
+       case TUP(PCEP_ERRT_INVALID_OPERATION,
+                PCEP_ERRV_LSP_INIT_NON_ZERO_PLSP_ID):
+               return "LSP_INIT_NON_ZERO_PLSP_I";
+       case TUP(PCEP_ERRT_INVALID_OPERATION, PCEP_ERRV_LSP_NOT_PCE_INITIATED):
+               return "LSP_NOT_PCE_INITIATE";
+       case TUP(PCEP_ERRT_INVALID_OPERATION,
+                PCEP_ERRV_PCE_INIT_OP_FREQ_LIMIT_REACHED):
+               return "PCE_INIT_OP_FREQ_LIMIT_REACHE";
+       case TUP(PCEP_ERRT_INVALID_OPERATION,
+                PCEP_ERRV_LSP_REPORT_P2MP_NOT_ADVERTISED):
+               return "LSP_REPORT_P2MP_NOT_ADVERTISE";
+       case TUP(PCEP_ERRT_INVALID_OPERATION,
+                PCEP_ERRV_LSP_UPDATE_P2MP_NOT_ADVERTISED):
+               return "LSP_UPDATE_P2MP_NOT_ADVERTISE";
+       case TUP(PCEP_ERRT_INVALID_OPERATION,
+                PCEP_ERRV_LSP_INSTANTIATION_P2MP_NOT_ADVERTISED):
+               return "LSP_INSTANTIATION_P2MP_NOT_ADVERTISE";
+       case TUP(PCEP_ERRT_INVALID_OPERATION,
+                PCEP_ERRV_AUTO_BW_CAP_NOT_ADVERTISED):
+               return "AUTO_BW_CAP_NOT_ADVERTISE";
+
+       case TUP(PCEP_ERRT_LSP_STATE_SYNC_ERROR,
+                PCEP_ERRV_PCE_CANT_PROCESS_LSP_REPORT):
+               return "PCE_CANT_PROCESS_LSP_REPORT";
+       case TUP(PCEP_ERRT_LSP_STATE_SYNC_ERROR,
+                PCEP_ERRV_LSP_DB_VERSION_MISMATCH):
+               return "LSP_DB_VERSION_MISMATCH";
+       case TUP(PCEP_ERRT_LSP_STATE_SYNC_ERROR,
+                PCEP_ERRV_TRIGGER_ATTEMPT_BEFORE_PCE_TRIGGER):
+               return "TRIGGER_ATTEMPT_BEFORE_PCE_TRIGGER";
+       case TUP(PCEP_ERRT_LSP_STATE_SYNC_ERROR,
+                PCEP_ERRV_TRIGGER_ATTEMPT_NO_PCE_TRIGGER_CAP):
+               return "TRIGGER_ATTEMPT_NO_PCE_TRIGGER_CAP";
+       case TUP(PCEP_ERRT_LSP_STATE_SYNC_ERROR,
+                PCEP_ERRV_PCC_CANT_COMPLETE_STATE_SYNC):
+               return "PCC_CANT_COMPLETE_STATE_SYNC";
+       case TUP(PCEP_ERRT_LSP_STATE_SYNC_ERROR,
+                PCEP_ERRV_INVALID_LSP_DB_VERSION_NUMBER):
+               return "INVALID_LSP_DB_VERSION_NUMBER";
+       case TUP(PCEP_ERRT_LSP_STATE_SYNC_ERROR,
+                PCEP_ERRV_INVALID_SPEAKER_ENTITY_ID):
+               return "INVALID_SPEAKER_ENTITY_ID";
+
+       case TUP(PCEP_ERRT_INVALID_TE_PATH_SETUP_TYPE,
+                PCEP_ERRV_UNSUPPORTED_PATH_SETUP_TYPE):
+               return "UNSUPPORTED_PATH_SETUP_TYPE";
+       case TUP(PCEP_ERRT_INVALID_TE_PATH_SETUP_TYPE,
+                PCEP_ERRV_MISMATCHED_PATH_SETUP_TYPE):
+               return "MISMATCHED_PATH_SETUP_TYPE";
+
+       case TUP(PCEP_ERRT_BAD_PARAMETER_VALUE,
+                PCEP_ERRV_SYMBOLIC_PATH_NAME_IN_USE):
+               return "SYMBOLIC_PATH_NAME_IN_USE";
+       case TUP(PCEP_ERRT_BAD_PARAMETER_VALUE,
+                PCEP_ERRV_LSP_SPEAKER_ID_NOT_PCE_INITIATED):
+               return "LSP_SPEAKER_ID_NOT_PCE_INITIATED";
+
+       case TUP(PCEP_ERRT_LSP_INSTANTIATE_ERROR,
+                PCEP_ERRV_UNACCEPTABLE_INSTANTIATE_ERROR):
+               return "UNACCEPTABLE_INSTANTIATE_ERROR";
+       case TUP(PCEP_ERRT_LSP_INSTANTIATE_ERROR, PCEP_ERRV_INTERNAL_ERROR):
+               return "INTERNAL_ERROR";
+       case TUP(PCEP_ERRT_LSP_INSTANTIATE_ERROR, PCEP_ERRV_SIGNALLING_ERROR):
+               return "SIGNALLING_ERROR";
+
+       case TUP(PCEP_ERRT_START_TLS_FAILURE,
+                PCEP_ERRV_START_TLS_AFTER_PCEP_EXCHANGE):
+               return "START_TLS_AFTER_PCEP_EXCHANGE";
+       case TUP(PCEP_ERRT_START_TLS_FAILURE,
+                PCEP_ERRV_MSG_NOT_START_TLS_OPEN_ERROR):
+               return "MSG_NOT_START_TLS_OPEN_ERROR";
+       case TUP(PCEP_ERRT_START_TLS_FAILURE,
+                PCEP_ERRV_CONNECTION_WO_TLS_NOT_POSSIBLE):
+               return "CONNECTION_WO_TLS_NOT_POSSIBLE";
+       case TUP(PCEP_ERRT_START_TLS_FAILURE,
+                PCEP_ERRV_CONNECTION_WO_TLS_IS_POSSIBLE):
+               return "CONNECTION_WO_TLS_IS_POSSIBLE";
+       case TUP(PCEP_ERRT_START_TLS_FAILURE,
+                PCEP_ERRV_NO_START_TLS_BEFORE_START_TLS_WAIT_TIMER):
+               return "NO_START_TLS_BEFORE_START_TLS_WAIT_TIMER";
+
+       case TUP(PCEP_ERRT_ASSOCIATION_ERROR,
+                PCEP_ERRV_ASSOC_TYPE_NOT_SUPPORTED):
+               return "ASSOC_TYPE_NOT_SUPPORTED";
+       case TUP(PCEP_ERRT_ASSOCIATION_ERROR,
+                PCEP_ERRV_TOO_MANY_LSPS_IN_ASSOC_GRP):
+               return "TOO_MANY_LSPS_IN_ASSOC_GRP";
+       case TUP(PCEP_ERRT_ASSOCIATION_ERROR, PCEP_ERRV_TOO_MANY_ASSOC_GROUPS):
+               return "TOO_MANY_ASSOC_GROUPS";
+       case TUP(PCEP_ERRT_ASSOCIATION_ERROR, PCEP_ERRV_ASSOCIATION_UNKNOWN):
+               return "ASSOCIATION_UNKNOWN";
+       case TUP(PCEP_ERRT_ASSOCIATION_ERROR,
+                PCEP_ERRV_OP_CONF_ASSOC_INFO_MISMATCH):
+               return "OP_CONF_ASSOC_INFO_MISMATCH";
+       case TUP(PCEP_ERRT_ASSOCIATION_ERROR, PCEP_ERRV_ASSOC_INFO_MISMATCH):
+               return "ASSOC_INFO_MISMATCH";
+       case TUP(PCEP_ERRT_ASSOCIATION_ERROR,
+                PCEP_ERRV_CANNOT_JOIN_ASSOC_GROUP):
+               return "CANNOT_JOIN_ASSOC_GROUP";
+       case TUP(PCEP_ERRT_ASSOCIATION_ERROR, PCEP_ERRV_ASSOC_ID_NOT_IN_RANGE):
+               return "ASSOC_ID_NOT_IN_RANGE";
+       case TUP(PCEP_ERRT_ASSOCIATION_ERROR,
+                PCEP_ERRV_TUNNEL_EP_MISMATCH_PATH_PROT_ASSOC):
+               return "TUNNEL_EP_MISMATCH_PATH_PROT_ASSOC";
+       case TUP(PCEP_ERRT_ASSOCIATION_ERROR,
+                PCEP_ERRV_ATTEMPTED_ADD_LSP_PATH_PROT_ASSOC):
+               return "ATTEMPTED_ADD_LSP_PATH_PROT_ASSOC";
+       case TUP(PCEP_ERRT_ASSOCIATION_ERROR,
+                PCEP_ERRV_PROTECTION_TYPE_NOT_SUPPORTED):
+               return "PROTECTION_TYPE_NOT_SUPPORTED";
+
+       case TUP(PCEP_ERRT_WSON_RWA_ERROR, PCEP_ERRV_RWA_INSUFFICIENT_MEMORY):
+               return "RWA_INSUFFICIENT_MEMORY";
+       case TUP(PCEP_ERRT_WSON_RWA_ERROR, PCEP_ERRV_RWA_COMP_NOT_SUPPORTED):
+               return "RWA_COMP_NOT_SUPPORTED";
+       case TUP(PCEP_ERRT_WSON_RWA_ERROR, PCEP_ERRV_SYNTAX_ENC_ERROR):
+               return "SYNTAX_ENC_ERROR";
+
+       case TUP(PCEP_ERRT_H_PCE_ERROR, PCEP_ERRV_H_PCE_CAP_NOT_ADVERTISED):
+               return "H_PCE_CAP_NOT_ADVERTISED";
+       case TUP(PCEP_ERRT_H_PCE_ERROR,
+                PCEP_ERRV_PARENT_PCE_CAP_CANT_BE_PROVIDED):
+               return "PARENT_PCE_CAP_CANT_BE_PROVIDED";
+
+       case TUP(PCEP_ERRT_PATH_COMP_FAILURE,
+                PCEP_ERRV_UNACCEPTABLE_REQUEST_MSG):
+               return "UNACCEPTABLE_REQUEST_MSG";
+       case TUP(PCEP_ERRT_PATH_COMP_FAILURE,
+                PCEP_ERRV_GENERALIZED_BW_VAL_NOT_SUPPORTED):
+               return "GENERALIZED_BW_VAL_NOT_SUPPORTED";
+       case TUP(PCEP_ERRT_PATH_COMP_FAILURE,
+                PCEP_ERRV_LABEL_SET_CONSTRAINT_COULD_NOT_BE_MET):
+               return "LABEL_SET_CONSTRAINT_COULD_NOT_BE_MET";
+       case TUP(PCEP_ERRT_PATH_COMP_FAILURE,
+                PCEP_ERRV_LABEL_CONSTRAINT_COULD_NOT_BE_MET):
+               return "LABEL_CONSTRAINT_COULD_NOT_BE_MET";
+
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *pcep_message_type_name(enum pcep_message_types pcep_message_type)
+{
+       switch (pcep_message_type) {
+
+       case PCEP_TYPE_OPEN:
+               return "OPEN";
+       case PCEP_TYPE_KEEPALIVE:
+               return "KEEPALIVE";
+       case PCEP_TYPE_PCREQ:
+               return "PCREQ";
+       case PCEP_TYPE_PCREP:
+               return "PCREP";
+       case PCEP_TYPE_PCNOTF:
+               return "PCNOTF";
+       case PCEP_TYPE_ERROR:
+               return "ERROR";
+       case PCEP_TYPE_CLOSE:
+               return "CLOSE";
+       case PCEP_TYPE_REPORT:
+               return "REPORT";
+       case PCEP_TYPE_UPDATE:
+               return "UPDATE";
+       case PCEP_TYPE_INITIATE:
+               return "INITIATE";
+       case PCEP_TYPE_UNKOWN_MSG:
+               return "UNKOWN_MSG";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *pcep_object_class_name(enum pcep_object_classes obj_class)
+{
+       switch (obj_class) {
+       case PCEP_OBJ_CLASS_OPEN:
+               return "OPEN";
+       case PCEP_OBJ_CLASS_RP:
+               return "RP";
+       case PCEP_OBJ_CLASS_NOPATH:
+               return "NOPATH";
+       case PCEP_OBJ_CLASS_ENDPOINTS:
+               return "ENDPOINTS";
+       case PCEP_OBJ_CLASS_BANDWIDTH:
+               return "BANDWIDTH";
+       case PCEP_OBJ_CLASS_METRIC:
+               return "METRIC";
+       case PCEP_OBJ_CLASS_ERO:
+               return "ERO";
+       case PCEP_OBJ_CLASS_RRO:
+               return "RRO";
+       case PCEP_OBJ_CLASS_LSPA:
+               return "LSPA";
+       case PCEP_OBJ_CLASS_IRO:
+               return "IRO";
+       case PCEP_OBJ_CLASS_SVEC:
+               return "SVEC";
+       case PCEP_OBJ_CLASS_NOTF:
+               return "NOTF";
+       case PCEP_OBJ_CLASS_ERROR:
+               return "ERROR";
+       case PCEP_OBJ_CLASS_CLOSE:
+               return "CLOSE";
+       case PCEP_OBJ_CLASS_OF:
+               return "OF";
+       case PCEP_OBJ_CLASS_LSP:
+               return "LSP";
+       case PCEP_OBJ_CLASS_SRP:
+               return "SRP";
+       case PCEP_OBJ_CLASS_VENDOR_INFO:
+               return "VENDOR_INFO";
+       case PCEP_OBJ_CLASS_INTER_LAYER:
+               return "INTER_LAYER";
+       case PCEP_OBJ_CLASS_SWITCH_LAYER:
+               return "SWITCH_LAYER";
+       case PCEP_OBJ_CLASS_REQ_ADAP_CAP:
+               return "REQ_ADAP_CAP";
+       case PCEP_OBJ_CLASS_SERVER_IND:
+               return "SERVER_IND";
+       case PCEP_OBJ_CLASS_ASSOCIATION:
+               return "ASSOCIATION";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *pcep_object_type_name(enum pcep_object_classes obj_class,
+                                 enum pcep_object_types obj_type)
+{
+       switch (TUP(obj_class, obj_type)) {
+       case TUP(PCEP_OBJ_CLASS_OPEN, PCEP_OBJ_TYPE_OPEN):
+               return "OPEN";
+       case TUP(PCEP_OBJ_CLASS_RP, PCEP_OBJ_TYPE_RP):
+               return "RP";
+       case TUP(PCEP_OBJ_CLASS_NOPATH, PCEP_OBJ_TYPE_NOPATH):
+               return "NOPATH";
+       case TUP(PCEP_OBJ_CLASS_ENDPOINTS, PCEP_OBJ_TYPE_ENDPOINT_IPV4):
+               return "ENDPOINT_IPV4";
+       case TUP(PCEP_OBJ_CLASS_ENDPOINTS, PCEP_OBJ_TYPE_ENDPOINT_IPV6):
+               return "ENDPOINT_IPV6";
+       case TUP(PCEP_OBJ_CLASS_BANDWIDTH, PCEP_OBJ_TYPE_BANDWIDTH_REQ):
+               return "BANDWIDTH_REQ";
+       case TUP(PCEP_OBJ_CLASS_BANDWIDTH, PCEP_OBJ_TYPE_BANDWIDTH_TELSP):
+               return "BANDWIDTH_TELSP";
+       case TUP(PCEP_OBJ_CLASS_BANDWIDTH, PCEP_OBJ_TYPE_BANDWIDTH_CISCO):
+               return "BANDWIDTH_CISCO";
+       case TUP(PCEP_OBJ_CLASS_METRIC, PCEP_OBJ_TYPE_METRIC):
+               return "METRIC";
+       case TUP(PCEP_OBJ_CLASS_ERO, PCEP_OBJ_TYPE_ERO):
+               return "ERO";
+       case TUP(PCEP_OBJ_CLASS_RRO, PCEP_OBJ_TYPE_RRO):
+               return "RRO";
+       case TUP(PCEP_OBJ_CLASS_LSPA, PCEP_OBJ_TYPE_LSPA):
+               return "LSPA";
+       case TUP(PCEP_OBJ_CLASS_IRO, PCEP_OBJ_TYPE_IRO):
+               return "IRO";
+       case TUP(PCEP_OBJ_CLASS_SVEC, PCEP_OBJ_TYPE_SVEC):
+               return "SVEC";
+       case TUP(PCEP_OBJ_CLASS_NOTF, PCEP_OBJ_TYPE_NOTF):
+               return "NOTF";
+       case TUP(PCEP_OBJ_CLASS_ERROR, PCEP_OBJ_TYPE_ERROR):
+               return "ERROR";
+       case TUP(PCEP_OBJ_CLASS_CLOSE, PCEP_OBJ_TYPE_CLOSE):
+               return "CLOSE";
+       case TUP(PCEP_OBJ_CLASS_INTER_LAYER, PCEP_OBJ_TYPE_INTER_LAYER):
+               return "INTER_LAYER";
+       case TUP(PCEP_OBJ_CLASS_SWITCH_LAYER, PCEP_OBJ_TYPE_SWITCH_LAYER):
+               return "SWITCH_LAYER";
+       case TUP(PCEP_OBJ_CLASS_REQ_ADAP_CAP, PCEP_OBJ_TYPE_REQ_ADAP_CAP):
+               return "REQ_ADAP_CAP";
+       case TUP(PCEP_OBJ_CLASS_SERVER_IND, PCEP_OBJ_TYPE_SERVER_IND):
+               return "SERVER_IND";
+       case TUP(PCEP_OBJ_CLASS_ASSOCIATION, PCEP_OBJ_TYPE_ASSOCIATION_IPV4):
+               return "ASSOCIATION_IPV4";
+       case TUP(PCEP_OBJ_CLASS_ASSOCIATION, PCEP_OBJ_TYPE_ASSOCIATION_IPV6):
+               return "ASSOCIATION_IPV6";
+       case TUP(PCEP_OBJ_CLASS_OF, PCEP_OBJ_TYPE_OF):
+               return "OF";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *pcep_lsp_status_name(enum pcep_lsp_operational_status status)
+{
+       switch (status) {
+       case PCEP_LSP_OPERATIONAL_DOWN:
+               return "DOWN";
+       case PCEP_LSP_OPERATIONAL_UP:
+               return "UP";
+       case PCEP_LSP_OPERATIONAL_ACTIVE:
+               return "ACTIVE";
+       case PCEP_LSP_OPERATIONAL_GOING_DOWN:
+               return "GOING_DOWN";
+       case PCEP_LSP_OPERATIONAL_GOING_UP:
+               return "GOING_UP";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+
+const char *pcep_tlv_type_name(enum pcep_object_tlv_types tlv_type)
+{
+       switch (tlv_type) {
+       case PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR:
+               return "NO_PATH_VECTOR";
+       case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY:
+               return "STATEFUL_PCE_CAPABILITY";
+       case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME:
+               return "SYMBOLIC_PATH_NAME";
+       case PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS:
+               return "IPV4_LSP_IDENTIFIERS";
+       case PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS:
+               return "IPV6_LSP_IDENTIFIERS";
+       case PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE:
+               return "LSP_ERROR_CODE";
+       case PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC:
+               return "RSVP_ERROR_SPEC";
+       case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION:
+               return "LSP_DB_VERSION";
+       case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID:
+               return "SPEAKER_ENTITY_ID";
+       case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY:
+               return "SR_PCE_CAPABILITY";
+       case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE:
+               return "PATH_SETUP_TYPE";
+       case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY:
+               return "PATH_SETUP_TYPE_CAPABILITY";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *pcep_ro_type_name(enum pcep_ro_subobj_types ro_type)
+{
+       switch (ro_type) {
+
+       case RO_SUBOBJ_TYPE_IPV4:
+               return "IPV4";
+       case RO_SUBOBJ_TYPE_IPV6:
+               return "IPV6";
+       case RO_SUBOBJ_TYPE_LABEL:
+               return "LABEL";
+       case RO_SUBOBJ_TYPE_UNNUM:
+               return "UNNUM";
+       case RO_SUBOBJ_TYPE_ASN:
+               return "ASN";
+       case RO_SUBOBJ_TYPE_SR:
+               return "SR";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *pcep_nai_type_name(enum pcep_sr_subobj_nai nai_type)
+{
+       switch (nai_type) {
+       case PCEP_SR_SUBOBJ_NAI_ABSENT:
+               return "ABSENT";
+       case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
+               return "IPV4_NODE";
+       case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
+               return "IPV6_NODE";
+       case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
+               return "IPV4_ADJACENCY";
+       case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
+               return "IPV6_ADJACENCY";
+       case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
+               return "UNNUMBERED_IPV4_ADJACENCY";
+       case PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY:
+               return "LINK_LOCAL_IPV6_ADJACENCY";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *pcep_metric_type_name(enum pcep_metric_types type)
+{
+       switch (type) {
+       case PCEP_METRIC_IGP:
+               return "IGP";
+       case PCEP_METRIC_TE:
+               return "TE";
+       case PCEP_METRIC_HOP_COUNT:
+               return "HOP_COUNT";
+       case PCEP_METRIC_AGGREGATE_BW:
+               return "AGGREGATE_BW";
+       case PCEP_METRIC_MOST_LOADED_LINK:
+               return "MOST_LOADED_LINK";
+       case PCEP_METRIC_CUMULATIVE_IGP:
+               return "CUMULATIVE_IGP";
+       case PCEP_METRIC_CUMULATIVE_TE:
+               return "CUMULATIVE_TE";
+       case PCEP_METRIC_P2MP_IGP:
+               return "P2MP_IGP";
+       case PCEP_METRIC_P2MP_TE:
+               return "P2MP_TE";
+       case PCEP_METRIC_P2MP_HOP_COUNT:
+               return "P2MP_HOP_COUNT";
+       case PCEP_METRIC_SEGMENT_ID_DEPTH:
+               return "SEGMENT_ID_DEPTH";
+       case PCEP_METRIC_PATH_DELAY:
+               return "PATH_DELAY";
+       case PCEP_METRIC_PATH_DELAY_VARIATION:
+               return "PATH_DELAY_VARIATION";
+       case PCEP_METRIC_PATH_LOSS:
+               return "PATH_LOSS";
+       case PCEP_METRIC_P2MP_PATH_DELAY:
+               return "P2MP_PATH_DELAY";
+       case PCEP_METRIC_P2MP_PATH_DELAY_VARIATION:
+               return "P2MP_PATH_DELAY_VARIATION";
+       case PCEP_METRIC_P2MP_PATH_LOSS:
+               return "P2MP_PATH_LOSS";
+       case PCEP_METRIC_NUM_PATH_ADAPTATIONS:
+               return "NUM_PATH_ADAPTATIONS";
+       case PCEP_METRIC_NUM_PATH_LAYERS:
+               return "NUM_PATH_LAYERS";
+       case PCEP_METRIC_DOMAIN_COUNT:
+               return "DOMAIN_COUNT";
+       case PCEP_METRIC_BORDER_NODE_COUNT:
+               return "BORDER_NODE_COUNT";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *pcep_nopath_tlv_err_code_name(enum pcep_nopath_tlv_err_codes type)
+{
+       switch (type) {
+       case PCEP_NOPATH_TLV_ERR_NO_TLV:
+               return "NO_TLV";
+       case PCEP_NOPATH_TLV_ERR_PCE_UNAVAILABLE:
+               return "PCE_UNAVAILABLE";
+       case PCEP_NOPATH_TLV_ERR_UNKNOWN_DST:
+               return "UNKNOWN_DST";
+       case PCEP_NOPATH_TLV_ERR_UNKNOWN_SRC:
+               return "UNKNOWN_SRC";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *format_objfun_set(uint32_t flags)
+{
+       int i, c;
+       PATHD_FORMAT_INIT();
+       for (i = 1, c = 0; i <= MAX_OBJFUN_TYPE; i++) {
+               if (CHECK_FLAG(flags, i)) {
+                       if (c > 0)
+                               PATHD_FORMAT(", %s", objfun_type_name(i));
+                       else
+                               PATHD_FORMAT("%s", objfun_type_name(i));
+                       c++;
+               }
+       }
+       return PATHD_FORMAT_FINI();
+}
+
+
+const char *format_pcc_opts(struct pcc_opts *opts)
+{
+       PATHD_FORMAT_INIT();
+       _format_pcc_opts(0, opts);
+       return PATHD_FORMAT_FINI();
+}
+
+const char *format_pcc_state(struct pcc_state *state)
+{
+       PATHD_FORMAT_INIT();
+       _format_pcc_state(0, state);
+       return PATHD_FORMAT_FINI();
+}
+
+const char *format_ctrl_state(struct ctrl_state *state)
+{
+       PATHD_FORMAT_INIT();
+       _format_ctrl_state(0, state);
+       return PATHD_FORMAT_FINI();
+}
+
+const char *format_path(struct path *path)
+{
+       PATHD_FORMAT_INIT();
+       _format_path(0, path);
+       return PATHD_FORMAT_FINI();
+}
+
+const char *format_pcep_event(pcep_event *event)
+{
+       PATHD_FORMAT_INIT();
+       _format_pcep_event(0, event);
+       return PATHD_FORMAT_FINI();
+}
+
+const char *format_pcep_message(struct pcep_message *msg)
+{
+       PATHD_FORMAT_INIT();
+       _format_pcep_message(0, msg);
+       return PATHD_FORMAT_FINI();
+}
+
+const char *format_yang_dnode(struct lyd_node *dnode)
+{
+       char *buff;
+       int len;
+
+       lyd_print_mem(&buff, dnode, LYD_JSON, LYP_FORMAT);
+       len = strlen(buff);
+       memcpy(_debug_buff, buff, len);
+       free(buff);
+       return _debug_buff;
+}
+
+void _format_pcc_opts(int ps, struct pcc_opts *opts)
+{
+       if (opts == NULL) {
+               PATHD_FORMAT("NULL\n");
+       } else {
+               int ps2 = ps + DEBUG_IDENT_SIZE;
+               PATHD_FORMAT("\n");
+               if (IS_IPADDR_V4(&opts->addr)) {
+                       PATHD_FORMAT("%*saddr_v4: %pI4\n", ps2, "",
+                                    &opts->addr.ipaddr_v4);
+               } else {
+                       PATHD_FORMAT("%*saddr_v4: undefined", ps2, "");
+               }
+               if (IS_IPADDR_V6(&opts->addr)) {
+                       PATHD_FORMAT("%*saddr_v6: %pI6\n", ps2, "",
+                                    &opts->addr.ipaddr_v6);
+               } else {
+                       PATHD_FORMAT("%*saddr_v6: undefined", ps2, "");
+               }
+               PATHD_FORMAT("%*sport: %i\n", ps2, "", opts->port);
+               PATHD_FORMAT("%*smsd: %i\n", ps2, "", opts->msd);
+       }
+}
+
+void _format_pce_opts(int ps, struct pce_opts *opts)
+{
+       if (opts == NULL) {
+               PATHD_FORMAT("NULL\n");
+       } else {
+               int ps2 = ps + DEBUG_IDENT_SIZE;
+               PATHD_FORMAT("\n");
+               if (IS_IPADDR_V6(&opts->addr)) {
+                       PATHD_FORMAT("%*saddr: %pI6\n", ps2, "",
+                                    &opts->addr.ipaddr_v6);
+               } else {
+                       PATHD_FORMAT("%*saddr: %pI4\n", ps2, "",
+                                    &opts->addr.ipaddr_v4);
+               }
+               PATHD_FORMAT("%*sport: %i\n", ps2, "", opts->port);
+       }
+}
+
+void _format_pcc_caps(int ps, struct pcep_caps *caps)
+{
+       int ps2 = ps + DEBUG_IDENT_SIZE;
+       PATHD_FORMAT("\n");
+       PATHD_FORMAT("%*sis_stateful: %d\n", ps2, "", caps->is_stateful);
+}
+
+void _format_pcc_state(int ps, struct pcc_state *state)
+{
+       if (state == NULL) {
+               PATHD_FORMAT("NULL\n");
+       } else {
+               int ps2 = ps + DEBUG_IDENT_SIZE;
+               PATHD_FORMAT("\n");
+               PATHD_FORMAT("%*sstatus: %s\n", ps2, "",
+                            pcc_status_name(state->status));
+               PATHD_FORMAT("%*spcc_opts: ", ps2, "");
+               _format_pcc_opts(ps2, state->pcc_opts);
+               PATHD_FORMAT("%*spce_opts: ", ps2, "");
+               _format_pce_opts(ps2, state->pce_opts);
+               if (state->sess == NULL) {
+                       PATHD_FORMAT("%*ssess: NULL\n", ps2, "");
+               } else {
+                       PATHD_FORMAT("%*ssess: <PCC SESSION %p>\n", ps2, "",
+                                    state->sess);
+               }
+               PATHD_FORMAT("%*scaps: ", ps2, "");
+               _format_pcc_caps(ps2, &state->caps);
+       }
+}
+
+void _format_ctrl_state(int ps, struct ctrl_state *state)
+{
+       if (state == NULL) {
+               PATHD_FORMAT("NULL\n");
+       } else {
+               int i;
+               int ps2 = ps + DEBUG_IDENT_SIZE;
+               int ps3 = ps2 + DEBUG_IDENT_SIZE;
+               PATHD_FORMAT("\n");
+               if (state->main == NULL) {
+                       PATHD_FORMAT("%*smain: NULL\n", ps2, "");
+               } else {
+                       PATHD_FORMAT("%*smain: <THREAD MASTER %p>\n", ps2, "",
+                                    state->main);
+               }
+               if (state->self == NULL) {
+                       PATHD_FORMAT("%*sself: NULL\n", ps2, "");
+               } else {
+                       PATHD_FORMAT("%*sself: <THREAD MASTER %p>\n", ps2, "",
+                                    state->self);
+               }
+               PATHD_FORMAT("%*spcc_count: %d\n", ps2, "", state->pcc_count);
+               PATHD_FORMAT("%*spcc:\n", ps2, "");
+               for (i = 0; i < MAX_PCC; i++) {
+                       if (state->pcc[i]) {
+                               PATHD_FORMAT("%*s- ", ps3 - 2, "");
+                               _format_pcc_state(ps3, state->pcc[i]);
+                       }
+               }
+       }
+}
+
+void _format_path(int ps, struct path *path)
+{
+       if (path == NULL) {
+               PATHD_FORMAT("NULL\n");
+       } else {
+               int ps2 = ps + DEBUG_IDENT_SIZE;
+               int ps3 = ps2 + DEBUG_IDENT_SIZE;
+               PATHD_FORMAT("\n");
+               PATHD_FORMAT("%*snbkey: \n", ps2, "");
+               PATHD_FORMAT("%*scolor: %u\n", ps3, "", path->nbkey.color);
+               switch (path->nbkey.endpoint.ipa_type) {
+               case IPADDR_V4:
+                       PATHD_FORMAT("%*sendpoint: %pI4\n", ps3, "",
+                                    &path->nbkey.endpoint.ipaddr_v4);
+                       break;
+               case IPADDR_V6:
+                       PATHD_FORMAT("%*sendpoint: %pI6\n", ps3, "",
+                                    &path->nbkey.endpoint.ipaddr_v6);
+                       break;
+               default:
+                       PATHD_FORMAT("%*sendpoint: NONE\n", ps3, "");
+                       break;
+               }
+               PATHD_FORMAT("%*spreference: %u\n", ps3, "",
+                            path->nbkey.preference);
+
+               if (path->sender.ipa_type == IPADDR_V4) {
+                       PATHD_FORMAT("%*ssender: %pI4\n", ps2, "",
+                                    &path->sender.ipaddr_v4);
+               } else if (path->sender.ipa_type == IPADDR_V6) {
+                       PATHD_FORMAT("%*ssender: %pI6\n", ps2, "",
+                                    &path->sender.ipaddr_v6);
+               } else {
+                       PATHD_FORMAT("%*ssender: UNDEFINED\n", ps2, "");
+               }
+               if (path->pcc_addr.ipa_type == IPADDR_V4) {
+                       PATHD_FORMAT("%*spcc_addr: %pI4\n", ps2, "",
+                                    &path->pcc_addr.ipaddr_v4);
+               } else if (path->pcc_addr.ipa_type == IPADDR_V6) {
+                       PATHD_FORMAT("%*spcc_addr: %pI6\n", ps2, "",
+                                    &path->pcc_addr.ipaddr_v6);
+               } else {
+                       PATHD_FORMAT("%*spcc_addr: UNDEFINED\n", ps2, "");
+               }
+               PATHD_FORMAT("%*spcc_id: %u\n", ps2, "", path->pcc_id);
+               PATHD_FORMAT("%*screate_origin: %s (%u)\n", ps2, "",
+                            srte_protocol_origin_name(path->create_origin),
+                            path->create_origin);
+               PATHD_FORMAT("%*supdate_origin: %s (%u)\n", ps2, "",
+                            srte_protocol_origin_name(path->update_origin),
+                            path->update_origin);
+               if (path->originator != NULL) {
+                       PATHD_FORMAT("%*soriginator: %s\n", ps2, "",
+                                    path->originator);
+               } else {
+                       PATHD_FORMAT("%*soriginator: UNDEFINED\n", ps2, "");
+               }
+               PATHD_FORMAT("%*stype: %s (%u)\n", ps2, "",
+                            srte_candidate_type_name(path->type), path->type);
+               PATHD_FORMAT("%*splsp_id: %u\n", ps2, "", path->plsp_id);
+               if (path->name == NULL) {
+                       PATHD_FORMAT("%*sname: NULL\n", ps2, "");
+               } else {
+                       PATHD_FORMAT("%*sname: %s\n", ps2, "", path->name);
+               }
+               PATHD_FORMAT("%*ssrp_id: %u\n", ps2, "", path->srp_id);
+               PATHD_FORMAT("%*sreq_id: %u\n", ps2, "", path->req_id);
+               PATHD_FORMAT("%*sstatus: %s (%u)\n", ps2, "",
+                            pcep_lsp_status_name(path->status), path->status);
+               PATHD_FORMAT("%*sdo_remove: %u\n", ps2, "", path->do_remove);
+               PATHD_FORMAT("%*sgo_active: %u\n", ps2, "", path->go_active);
+               PATHD_FORMAT("%*swas_created: %u\n", ps2, "",
+                            path->was_created);
+               PATHD_FORMAT("%*swas_removed: %u\n", ps2, "",
+                            path->was_removed);
+               PATHD_FORMAT("%*sis_synching: %u\n", ps2, "",
+                            path->is_synching);
+               PATHD_FORMAT("%*sis_delegated: %u\n", ps2, "",
+                            path->is_delegated);
+               PATHD_FORMAT("%*shas_bandwidth: %u\n", ps2, "",
+                            path->has_bandwidth);
+               if (path->has_bandwidth) {
+                       PATHD_FORMAT("%*senforce_bandwidth: %u\n", ps2, "",
+                                    path->enforce_bandwidth);
+                       PATHD_FORMAT("%*sbandwidth: %f\n", ps2, "",
+                                    path->bandwidth);
+               }
+               PATHD_FORMAT("%*shas_pcc_objfun: %u\n", ps2, "",
+                            path->has_pcc_objfun);
+               if (path->has_pcc_objfun) {
+                       PATHD_FORMAT("%*senforce_pcc_objfun: %d\n", ps2, "",
+                                    path->enforce_pcc_objfun);
+                       PATHD_FORMAT("%*spcc_objfun: %s (%u)\n", ps2, "",
+                                    objfun_type_name(path->pcc_objfun),
+                                    path->pcc_objfun);
+               }
+               PATHD_FORMAT("%*shas_pce_objfun: %u\n", ps2, "",
+                            path->has_pce_objfun);
+               if (path->has_pce_objfun)
+                       PATHD_FORMAT("%*spce_objfun: %s (%u)\n", ps2, "",
+                                    objfun_type_name(path->pce_objfun),
+                                    path->pce_objfun);
+               PATHD_FORMAT("%*shas_affinity_filters: %u\n", ps2, "",
+                            path->has_affinity_filters);
+               if (path->has_affinity_filters) {
+                       PATHD_FORMAT("%*sexclude_any: 0x%08x\n", ps2, "",
+                                    path->affinity_filters
+                                            [AFFINITY_FILTER_EXCLUDE_ANY - 1]);
+                       PATHD_FORMAT("%*sinclude_any: 0x%08x\n", ps2, "",
+                                    path->affinity_filters
+                                            [AFFINITY_FILTER_INCLUDE_ANY - 1]);
+                       PATHD_FORMAT("%*sinclude_all: 0x%08x\n", ps2, "",
+                                    path->affinity_filters
+                                            [AFFINITY_FILTER_INCLUDE_ALL - 1]);
+               }
+
+               if (path->first_hop == NULL) {
+                       PATHD_FORMAT("%*shops: []\n", ps2, "");
+               } else {
+                       PATHD_FORMAT("%*shops: \n", ps2, "");
+                       for (struct path_hop *hop = path->first_hop;
+                            hop != NULL; hop = hop->next) {
+                               PATHD_FORMAT("%*s- ", ps3 - 2, "");
+                               _format_path_hop(ps3, hop);
+                       }
+               }
+               if (path->first_metric == NULL) {
+                       PATHD_FORMAT("%*smetrics: []\n", ps2, "");
+               } else {
+                       PATHD_FORMAT("%*smetrics: \n", ps2, "");
+                       for (struct path_metric *metric = path->first_metric;
+                            NULL != metric; metric = metric->next) {
+                               PATHD_FORMAT("%*s- ", ps3 - 2, "");
+                               _format_path_metric(ps3, metric);
+                       }
+               }
+       }
+}
+
+void _format_path_metric(int ps, struct path_metric *metric)
+{
+       PATHD_FORMAT("type: %s (%u)\n", pcep_metric_type_name(metric->type),
+                    metric->type);
+       PATHD_FORMAT("%*senforce: %u\n", ps, "", metric->enforce);
+       PATHD_FORMAT("%*sis_bound: %u\n", ps, "", metric->is_bound);
+       PATHD_FORMAT("%*sis_computed: %u\n", ps, "", metric->is_computed);
+       PATHD_FORMAT("%*svalue: %f\n", ps, "", metric->value);
+}
+
+void _format_path_hop(int ps, struct path_hop *hop)
+{
+       PATHD_FORMAT("is_loose: %u\n", hop->is_loose);
+       PATHD_FORMAT("%*shas_sid: %u\n", ps, "", hop->has_sid);
+
+       if (hop->has_sid) {
+               PATHD_FORMAT("%*sis_mpls: %u\n", ps, "", hop->is_mpls);
+               if (hop->is_mpls) {
+                       PATHD_FORMAT("%*shas_attribs: %u\n", ps, "",
+                                    hop->has_attribs);
+                       PATHD_FORMAT("%*slabel: %u\n", ps, "",
+                                    hop->sid.mpls.label);
+                       if (hop->has_attribs) {
+                               PATHD_FORMAT("%*straffic_class: %u\n", ps, "",
+                                            hop->sid.mpls.traffic_class);
+                               PATHD_FORMAT("%*sis_bottom: %u\n", ps, "",
+                                            hop->sid.mpls.is_bottom);
+                               PATHD_FORMAT("%*sttl: %u\n", ps, "",
+                                            hop->sid.mpls.ttl);
+                       }
+               } else {
+                       PATHD_FORMAT("%*sSID: %u\n", ps, "", hop->sid.value);
+               }
+       }
+
+       PATHD_FORMAT("%*shas_nai: %u\n", ps, "", hop->has_nai);
+       if (hop->has_nai) {
+               PATHD_FORMAT("%*snai_type: %s (%u)\n", ps, "",
+                            pcep_nai_type_name(hop->nai.type), hop->nai.type);
+               switch (hop->nai.type) {
+               case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
+                       PATHD_FORMAT("%*sNAI: %pI4\n", ps, "",
+                                    &hop->nai.local_addr.ipaddr_v4);
+                       break;
+               case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
+                       PATHD_FORMAT("%*sNAI: %pI6\n", ps, "",
+                                    &hop->nai.local_addr.ipaddr_v6);
+                       break;
+               case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
+                       PATHD_FORMAT("%*sNAI: %pI4/%pI4\n", ps, "",
+                                    &hop->nai.local_addr.ipaddr_v4,
+                                    &hop->nai.remote_addr.ipaddr_v4);
+                       break;
+               case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
+                       PATHD_FORMAT("%*sNAI: %pI6/%pI6\n", ps, "",
+                                    &hop->nai.local_addr.ipaddr_v6,
+                                    &hop->nai.remote_addr.ipaddr_v6);
+                       break;
+               case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
+                       PATHD_FORMAT("%*sNAI: %pI4(%u)/%pI4(%u)\n", ps, "",
+                                    &hop->nai.local_addr.ipaddr_v6,
+                                    hop->nai.local_iface,
+                                    &hop->nai.remote_addr.ipaddr_v6,
+                                    hop->nai.remote_iface);
+                       break;
+               default:
+                       PATHD_FORMAT("%*sNAI: UNSUPPORTED\n", ps, "");
+                       break;
+               }
+       }
+}
+
+void _format_pcep_event(int ps, pcep_event *event)
+{
+       if (event == NULL) {
+               PATHD_FORMAT("NULL\n");
+       } else {
+               int ps2 = ps + DEBUG_IDENT_SIZE;
+               PATHD_FORMAT("\n");
+               PATHD_FORMAT("%*sevent_type: %s\n", ps2, "",
+                            pcep_event_type_name(event->event_type));
+               PATHD_FORMAT("%*sevent_time: %s", ps2, "",
+                            ctime(&event->event_time));
+               if (event->session == NULL) {
+                       PATHD_FORMAT("%*ssession: NULL\n", ps2, "");
+               } else {
+                       PATHD_FORMAT("%*ssession: <PCC SESSION %p>\n", ps2, "",
+                                    event->session);
+               }
+               PATHD_FORMAT("%*smessage: ", ps2, "");
+               _format_pcep_message(ps2, event->message);
+       }
+}
+
+void _format_pcep_message(int ps, struct pcep_message *msg)
+{
+       if (msg == NULL) {
+               PATHD_FORMAT("NULL\n");
+       } else {
+               int ps2 = ps + DEBUG_IDENT_SIZE;
+               PATHD_FORMAT("\n");
+               PATHD_FORMAT("%*spcep_version: %u\n", ps2, "",
+                            msg->msg_header->pcep_version);
+               PATHD_FORMAT("%*stype: %s (%u)\n", ps2, "",
+                            pcep_message_type_name(msg->msg_header->type),
+                            msg->msg_header->type);
+               PATHD_FORMAT("%*sobjects: ", ps2, "");
+               _format_pcep_objects(ps2, msg->obj_list);
+       }
+}
+
+void _format_pcep_objects(int ps, double_linked_list *objs)
+{
+       if (objs == NULL) {
+               PATHD_FORMAT("NULL\n");
+       } else {
+               double_linked_list_node *node;
+               int ps2 = ps + DEBUG_IDENT_SIZE;
+               int i;
+
+               if (objs->num_entries == 0) {
+                       PATHD_FORMAT("[]\n");
+                       return;
+               }
+
+               PATHD_FORMAT("\n");
+               for (node = objs->head, i = 0; node != NULL;
+                    node = node->next_node, i++) {
+                       struct pcep_object_header *obj =
+                               (struct pcep_object_header *)node->data;
+                       PATHD_FORMAT("%*s- ", ps2 - 2, "");
+                       _format_pcep_object(ps2, obj);
+               }
+       }
+}
+
+void _format_pcep_object(int ps, struct pcep_object_header *obj)
+{
+       if (obj == NULL) {
+               PATHD_FORMAT("NULL\n");
+       } else {
+               PATHD_FORMAT("object_class: %s (%u)\n",
+                            pcep_object_class_name(obj->object_class),
+                            obj->object_class);
+               PATHD_FORMAT("%*sobject_type: %s (%u)\n", ps, "",
+                            pcep_object_type_name(obj->object_class,
+                                                  obj->object_type),
+                            obj->object_type);
+               PATHD_FORMAT("%*sflag_p: %u\n", ps, "", obj->flag_p);
+               PATHD_FORMAT("%*sflag_i: %u\n", ps, "", obj->flag_i);
+               _format_pcep_object_details(ps, obj);
+               _format_pcep_object_tlvs(ps, obj);
+       }
+}
+
+void _format_pcep_object_details(int ps, struct pcep_object_header *obj)
+{
+       switch (TUP(obj->object_class, obj->object_type)) {
+       case TUP(PCEP_OBJ_CLASS_ERROR, PCEP_OBJ_TYPE_ERROR):
+               _format_pcep_object_error(ps, (struct pcep_object_error *)obj);
+               break;
+       case TUP(PCEP_OBJ_CLASS_OPEN, PCEP_OBJ_TYPE_OPEN):
+               _format_pcep_object_open(ps, (struct pcep_object_open *)obj);
+               break;
+       case TUP(PCEP_OBJ_CLASS_RP, PCEP_OBJ_TYPE_RP):
+               _format_pcep_object_rp(ps, (struct pcep_object_rp *)obj);
+               break;
+       case TUP(PCEP_OBJ_CLASS_SRP, PCEP_OBJ_TYPE_SRP):
+               _format_pcep_object_srp(ps, (struct pcep_object_srp *)obj);
+               break;
+       case TUP(PCEP_OBJ_CLASS_LSP, PCEP_OBJ_TYPE_LSP):
+               _format_pcep_object_lsp(ps, (struct pcep_object_lsp *)obj);
+               break;
+       case TUP(PCEP_OBJ_CLASS_LSPA, PCEP_OBJ_TYPE_LSPA):
+               _format_pcep_object_lspa(ps, (struct pcep_object_lspa *)obj);
+               break;
+       case TUP(PCEP_OBJ_CLASS_ENDPOINTS, PCEP_OBJ_TYPE_ENDPOINT_IPV4):
+               _format_pcep_object_ipv4_endpoint(
+                       ps, (struct pcep_object_endpoints_ipv4 *)obj);
+               break;
+       case TUP(PCEP_OBJ_CLASS_ERO, PCEP_OBJ_TYPE_ERO):
+               _format_pcep_object_ro(ps, (struct pcep_object_ro *)obj);
+               break;
+       case TUP(PCEP_OBJ_CLASS_METRIC, PCEP_OBJ_TYPE_METRIC):
+               _format_pcep_object_metric(ps,
+                                          (struct pcep_object_metric *)obj);
+               break;
+       case TUP(PCEP_OBJ_CLASS_BANDWIDTH, PCEP_OBJ_TYPE_BANDWIDTH_REQ):
+       case TUP(PCEP_OBJ_CLASS_BANDWIDTH, PCEP_OBJ_TYPE_BANDWIDTH_CISCO):
+               _format_pcep_object_bandwidth(
+                       ps, (struct pcep_object_bandwidth *)obj);
+               break;
+       case TUP(PCEP_OBJ_CLASS_NOPATH, PCEP_OBJ_TYPE_NOPATH):
+               _format_pcep_object_nopath(ps,
+                                          (struct pcep_object_nopath *)obj);
+               break;
+       case TUP(PCEP_OBJ_CLASS_OF, PCEP_OBJ_TYPE_OF):
+               _format_pcep_object_objfun(
+                       ps, (struct pcep_object_objective_function *)obj);
+               break;
+       default:
+               PATHD_FORMAT("%*s...\n", ps, "");
+               break;
+       }
+}
+
+void _format_pcep_object_error(int ps, struct pcep_object_error *obj)
+{
+       PATHD_FORMAT("%*serror_type: %s (%u)\n", ps, "",
+                    pcep_error_type_name(obj->error_type), obj->error_type);
+       PATHD_FORMAT("%*serror_value: %s (%u)\n", ps, "",
+                    pcep_error_value_name(obj->error_type, obj->error_value),
+                    obj->error_value);
+}
+
+
+void _format_pcep_object_open(int ps, struct pcep_object_open *obj)
+{
+       PATHD_FORMAT("%*sopen_version: %u\n", ps, "", obj->open_version);
+       PATHD_FORMAT("%*sopen_keepalive: %u\n", ps, "", obj->open_keepalive);
+       PATHD_FORMAT("%*sopen_deadtimer: %u\n", ps, "", obj->open_deadtimer);
+       PATHD_FORMAT("%*sopen_sid: %u\n", ps, "", obj->open_sid);
+}
+
+void _format_pcep_object_rp(int ps, struct pcep_object_rp *obj)
+{
+       PATHD_FORMAT("%*spriority: %u\n", ps, "", obj->priority);
+       PATHD_FORMAT("%*sflag_reoptimization: %u\n", ps, "",
+                    obj->flag_reoptimization);
+       PATHD_FORMAT("%*sflag_bidirectional: %u\n", ps, "",
+                    obj->flag_bidirectional);
+       PATHD_FORMAT("%*sflag_strict: %u\n", ps, "", obj->flag_strict);
+       PATHD_FORMAT("%*sflag_of: %u\n", ps, "", obj->flag_of);
+       PATHD_FORMAT("%*srequest_id: %u\n", ps, "", obj->request_id);
+}
+
+
+void _format_pcep_object_srp(int ps, struct pcep_object_srp *obj)
+{
+       PATHD_FORMAT("%*sflag_lsp_remove: %u\n", ps, "", obj->flag_lsp_remove);
+       PATHD_FORMAT("%*ssrp_id_number: %u\n", ps, "", obj->srp_id_number);
+}
+
+void _format_pcep_object_lsp(int ps, struct pcep_object_lsp *obj)
+{
+       PATHD_FORMAT("%*splsp_id: %u\n", ps, "", obj->plsp_id);
+       PATHD_FORMAT("%*sstatus: %s\n", ps, "",
+                    pcep_lsp_status_name(obj->operational_status));
+       PATHD_FORMAT("%*sflag_d: %u\n", ps, "", obj->flag_d);
+       PATHD_FORMAT("%*sflag_s: %u\n", ps, "", obj->flag_s);
+       PATHD_FORMAT("%*sflag_r: %u\n", ps, "", obj->flag_r);
+       PATHD_FORMAT("%*sflag_a: %u\n", ps, "", obj->flag_a);
+       PATHD_FORMAT("%*sflag_c: %u\n", ps, "", obj->flag_c);
+}
+
+void _format_pcep_object_lspa(int ps, struct pcep_object_lspa *obj)
+{
+       PATHD_FORMAT("%*slspa_exclude_any: 0x%08x\n", ps, "",
+                    obj->lspa_exclude_any);
+       PATHD_FORMAT("%*slspa_include_any: 0x%08x\n", ps, "",
+                    obj->lspa_include_any);
+       PATHD_FORMAT("%*slspa_include_all: 0x%08x\n", ps, "",
+                    obj->lspa_include_all);
+       PATHD_FORMAT("%*ssetup_priority: %u\n", ps, "", obj->setup_priority);
+       PATHD_FORMAT("%*sholding_priority: %u\n", ps, "",
+                    obj->holding_priority);
+       PATHD_FORMAT("%*sflag_local_protection: %u\n", ps, "",
+                    obj->flag_local_protection);
+}
+
+void _format_pcep_object_ipv4_endpoint(int ps,
+                                      struct pcep_object_endpoints_ipv4 *obj)
+{
+       PATHD_FORMAT("%*ssrc_ipv4: %pI4\n", ps, "", &obj->src_ipv4);
+       PATHD_FORMAT("%*sdst_ipv4: %pI4\n", ps, "", &obj->dst_ipv4);
+}
+
+void _format_pcep_object_metric(int ps, struct pcep_object_metric *obj)
+{
+       PATHD_FORMAT("%*stype: %s (%u)\n", ps, "",
+                    pcep_metric_type_name(obj->type), obj->type);
+       PATHD_FORMAT("%*sflag_b: %u\n", ps, "", obj->flag_b);
+       PATHD_FORMAT("%*sflag_c: %u\n", ps, "", obj->flag_c);
+       PATHD_FORMAT("%*svalue: %f\n", ps, "", obj->value);
+}
+
+void _format_pcep_object_bandwidth(int ps, struct pcep_object_bandwidth *obj)
+{
+       PATHD_FORMAT("%*sbandwidth: %f\n", ps, "", obj->bandwidth);
+}
+
+void _format_pcep_object_nopath(int ps, struct pcep_object_nopath *obj)
+{
+       PATHD_FORMAT("%*sni: %u\n", ps, "", obj->ni);
+       PATHD_FORMAT("%*sflag_c: %u\n", ps, "", obj->flag_c);
+       PATHD_FORMAT("%*serr_code: %s (%u)\n", ps, "",
+                    pcep_nopath_tlv_err_code_name(obj->err_code),
+                    obj->err_code);
+}
+
+void _format_pcep_object_objfun(int ps,
+                               struct pcep_object_objective_function *obj)
+{
+       PATHD_FORMAT("%*sof_code: %s (%u)\n", ps, "",
+                    objfun_type_name(obj->of_code), obj->of_code);
+}
+
+void _format_pcep_object_ro(int ps, struct pcep_object_ro *obj)
+{
+       double_linked_list *obj_list = obj->sub_objects;
+       double_linked_list_node *node;
+       struct pcep_object_ro_subobj *sub_obj;
+
+       int ps2 = ps + DEBUG_IDENT_SIZE;
+       int i;
+
+       if ((obj_list == NULL) || (obj_list->num_entries == 0)) {
+               PATHD_FORMAT("%*ssub_objects: []\n", ps, "");
+               return;
+       }
+
+       PATHD_FORMAT("%*ssub_objects:\n", ps, "");
+
+       for (node = obj_list->head, i = 0; node != NULL;
+            node = node->next_node, i++) {
+               sub_obj = (struct pcep_object_ro_subobj *)node->data;
+               PATHD_FORMAT("%*s- flag_subobj_loose_hop: %u\n", ps2 - 2, "",
+                            sub_obj->flag_subobj_loose_hop);
+               PATHD_FORMAT("%*sro_subobj_type: %s (%u)\n", ps2, "",
+                            pcep_ro_type_name(sub_obj->ro_subobj_type),
+                            sub_obj->ro_subobj_type);
+               _format_pcep_object_ro_details(ps2, sub_obj);
+       }
+}
+
+void _format_pcep_object_ro_details(int ps, struct pcep_object_ro_subobj *ro)
+{
+       switch (ro->ro_subobj_type) {
+       case RO_SUBOBJ_TYPE_IPV4:
+               _format_pcep_object_ro_ipv4(ps,
+                                           (struct pcep_ro_subobj_ipv4 *)ro);
+               break;
+       case RO_SUBOBJ_TYPE_SR:
+               _format_pcep_object_ro_sr(ps, (struct pcep_ro_subobj_sr *)ro);
+               break;
+       default:
+               PATHD_FORMAT("%*s...\n", ps, "");
+               break;
+       }
+}
+
+void _format_pcep_object_ro_ipv4(int ps, struct pcep_ro_subobj_ipv4 *obj)
+{
+       PATHD_FORMAT("%*sip_addr: %pI4\n", ps, "", &obj->ip_addr);
+       PATHD_FORMAT("%*sprefix_length: %u\n", ps, "", obj->prefix_length);
+       PATHD_FORMAT("%*sflag_local_protection: %u\n", ps, "",
+                    obj->flag_local_protection);
+}
+
+void _format_pcep_object_ro_sr(int ps, struct pcep_ro_subobj_sr *obj)
+{
+       PATHD_FORMAT("%*snai_type = %s (%u)\n", ps, "",
+                    pcep_nai_type_name(obj->nai_type), obj->nai_type);
+       PATHD_FORMAT("%*sflag_f: %u\n", ps, "", obj->flag_f);
+       PATHD_FORMAT("%*sflag_s: %u\n", ps, "", obj->flag_s);
+       PATHD_FORMAT("%*sflag_c: %u\n", ps, "", obj->flag_c);
+       PATHD_FORMAT("%*sflag_m: %u\n", ps, "", obj->flag_m);
+
+       if (!obj->flag_s) {
+               PATHD_FORMAT("%*sSID: %u\n", ps, "", obj->sid);
+               if (obj->flag_m) {
+                       PATHD_FORMAT("%*slabel: %u\n", ps, "",
+                                    GET_SR_ERO_SID_LABEL(obj->sid));
+                       if (obj->flag_c) {
+                               PATHD_FORMAT("%*sTC: %u\n", ps, "",
+                                            GET_SR_ERO_SID_TC(obj->sid));
+                               PATHD_FORMAT("%*sS: %u\n", ps, "",
+                                            GET_SR_ERO_SID_S(obj->sid));
+                               PATHD_FORMAT("%*sTTL: %u\n", ps, "",
+                                            GET_SR_ERO_SID_TTL(obj->sid));
+                       }
+               }
+       }
+
+       if (!obj->flag_f) {
+               struct in_addr *laddr4, *raddr4;
+               struct in6_addr *laddr6, *raddr6;
+               uint32_t *liface, *riface;
+               assert(obj->nai_list != NULL);
+               double_linked_list_node *n = obj->nai_list->head;
+               assert(n != NULL);
+               assert(n->data != NULL);
+               switch (obj->nai_type) {
+               case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
+                       laddr4 = (struct in_addr *)n->data;
+                       PATHD_FORMAT("%*sNAI: %pI4\n", ps, "", laddr4);
+                       break;
+               case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
+                       laddr6 = (struct in6_addr *)n->data;
+                       PATHD_FORMAT("%*sNAI: %pI6\n", ps, "", laddr6);
+                       break;
+               case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
+                       assert(n->next_node != NULL);
+                       assert(n->next_node->data != NULL);
+                       laddr4 = (struct in_addr *)n->data;
+                       raddr4 = (struct in_addr *)n->next_node->data;
+                       PATHD_FORMAT("%*sNAI: %pI4/%pI4\n", ps, "", laddr4,
+                                    raddr4);
+                       break;
+               case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
+                       assert(n->next_node != NULL);
+                       assert(n->next_node->data != NULL);
+                       laddr6 = (struct in6_addr *)n->data;
+                       raddr6 = (struct in6_addr *)n->next_node->data;
+                       PATHD_FORMAT("%*sNAI: %pI6/%pI6\n", ps, "", laddr6,
+                                    raddr6);
+                       break;
+               case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
+                       laddr4 = (struct in_addr *)n->data;
+                       n = n->next_node;
+                       assert(n != NULL);
+                       assert(n->data != NULL);
+                       liface = (uint32_t *)n->data;
+                       n = n->next_node;
+                       assert(n != NULL);
+                       assert(n->data != NULL);
+                       raddr4 = (struct in_addr *)n->data;
+                       assert(n != NULL);
+                       assert(n->data != NULL);
+                       riface = (uint32_t *)n->data;
+                       PATHD_FORMAT("%*sNAI: %pI4(%u)/%pI4(%u)\n", ps, "",
+                                    laddr4, *liface, raddr4, *riface);
+                       break;
+               default:
+                       PATHD_FORMAT("%*sNAI: UNSUPPORTED\n", ps, "");
+                       break;
+               }
+       }
+}
+
+void _format_pcep_object_tlvs(int ps, struct pcep_object_header *obj)
+{
+       double_linked_list *tlv_list = obj->tlv_list;
+       struct pcep_object_tlv_header *tlv;
+       double_linked_list_node *node;
+       int ps2 = ps + DEBUG_IDENT_SIZE;
+       int i = 0;
+
+       if (tlv_list == NULL)
+               return;
+       if (tlv_list->num_entries == 0) {
+               PATHD_FORMAT("%*stlvs: []\n", ps, "");
+               return;
+       }
+
+       PATHD_FORMAT("%*stlvs:\n", ps, "");
+
+       for (node = tlv_list->head, i = 0; node != NULL;
+            node = node->next_node, i++) {
+               tlv = (struct pcep_object_tlv_header *)node->data;
+               PATHD_FORMAT("%*s- ", ps2 - 2, "");
+               _format_pcep_object_tlv(ps2, tlv);
+       }
+}
+
+void _format_pcep_object_tlv(int ps, struct pcep_object_tlv_header *tlv_header)
+{
+       PATHD_FORMAT("type: %s (%u)\n", pcep_tlv_type_name(tlv_header->type),
+                    tlv_header->type);
+       _format_pcep_object_tlv_details(ps, tlv_header);
+}
+
+void _format_pcep_object_tlv_details(int ps,
+                                    struct pcep_object_tlv_header *tlv_header)
+{
+       switch (tlv_header->type) {
+       case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME:
+               _format_pcep_object_tlv_symbolic_path_name(
+                       ps, (struct pcep_object_tlv_symbolic_path_name *)
+                                   tlv_header);
+               break;
+       case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY:
+               _format_pcep_object_tlv_stateful_pce_capability(
+                       ps, (struct pcep_object_tlv_stateful_pce_capability *)
+                                   tlv_header);
+               break;
+       case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY:
+               _format_pcep_object_tlv_sr_pce_capability(
+                       ps,
+                       (struct pcep_object_tlv_sr_pce_capability *)tlv_header);
+               break;
+       case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE:
+               _format_pcep_object_tlv_path_setup_type(
+                       ps,
+                       (struct pcep_object_tlv_path_setup_type *)tlv_header);
+               break;
+       default:
+               PATHD_FORMAT("%*s...\n", ps, "");
+               break;
+       }
+}
+
+void _format_pcep_object_tlv_symbolic_path_name(
+       int ps, struct pcep_object_tlv_symbolic_path_name *tlv)
+{
+       PATHD_FORMAT("%*ssymbolic_path_name: %.*s\n", ps, "",
+                    tlv->symbolic_path_name_length, tlv->symbolic_path_name);
+}
+
+void _format_pcep_object_tlv_stateful_pce_capability(
+       int ps, struct pcep_object_tlv_stateful_pce_capability *tlv)
+{
+       PATHD_FORMAT("%*sflag_u_lsp_update_capability: %u\n", ps, "",
+                    tlv->flag_u_lsp_update_capability);
+       PATHD_FORMAT("%*sflag_s_include_db_version: %u\n", ps, "",
+                    tlv->flag_s_include_db_version);
+       PATHD_FORMAT("%*sflag_i_lsp_instantiation_capability: %u\n", ps, "",
+                    tlv->flag_i_lsp_instantiation_capability);
+       PATHD_FORMAT("%*sflag_t_triggered_resync: %u\n", ps, "",
+                    tlv->flag_t_triggered_resync);
+       PATHD_FORMAT("%*sflag_d_delta_lsp_sync: %u\n", ps, "",
+                    tlv->flag_d_delta_lsp_sync);
+       PATHD_FORMAT("%*sflag_f_triggered_initial_sync: %u\n", ps, "",
+                    tlv->flag_f_triggered_initial_sync);
+}
+
+void _format_pcep_object_tlv_sr_pce_capability(
+       int ps, struct pcep_object_tlv_sr_pce_capability *tlv)
+{
+
+       PATHD_FORMAT("%*sflag_n: %u\n", ps, "", tlv->flag_n);
+       PATHD_FORMAT("%*sflag_x: %u\n", ps, "", tlv->flag_x);
+       PATHD_FORMAT("%*smax_sid_depth: %u\n", ps, "", tlv->max_sid_depth);
+}
+
+void _format_pcep_object_tlv_path_setup_type(
+       int ps, struct pcep_object_tlv_path_setup_type *tlv)
+{
+       PATHD_FORMAT("%*spath_setup_type: %u\n", ps, "", tlv->path_setup_type);
+}
diff --git a/pathd/path_pcep_debug.h b/pathd/path_pcep_debug.h
new file mode 100644 (file)
index 0000000..68b29ab
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#ifndef _PATH_PCEP_DEBUG_H_
+#define _PATH_PCEP_DEBUG_H_
+
+#include "pathd/path_debug.h"
+#include <pcep_pcc_api.h>
+#include <pcep-objects.h>
+#include "pathd/path_pcep.h"
+#include "pathd/path_pcep_controller.h"
+#include "pathd/path_pcep_pcc.h"
+#include "pathd/path_pcep_lib.h"
+
+const char *pcc_status_name(enum pcc_status status);
+
+const char *pcep_error_type_name(enum pcep_error_type error_type);
+const char *pcep_error_value_name(enum pcep_error_type error_type,
+                                 enum pcep_error_value error_value);
+const char *pcep_event_type_name(pcep_event_type event_type);
+const char *pcep_message_type_name(enum pcep_message_types pcep_message_type);
+const char *pcep_object_class_name(enum pcep_object_classes obj_class);
+const char *pcep_object_type_name(enum pcep_object_classes obj_class,
+                                 enum pcep_object_types obj_type);
+const char *pcep_lsp_status_name(enum pcep_lsp_operational_status status);
+const char *pcep_tlv_type_name(enum pcep_object_tlv_types tlv_type);
+const char *pcep_ro_type_name(enum pcep_ro_subobj_types ro_type);
+const char *pcep_nai_type_name(enum pcep_sr_subobj_nai nai_type);
+const char *pcep_metric_type_name(enum pcep_metric_types type);
+const char *pcep_nopath_tlv_err_code_name(enum pcep_nopath_tlv_err_codes code);
+
+const char *format_objfun_set(uint32_t flags);
+const char *format_pcc_opts(struct pcc_opts *ops);
+const char *format_pcc_state(struct pcc_state *state);
+const char *format_ctrl_state(struct ctrl_state *state);
+const char *format_path(struct path *path);
+const char *format_pcep_event(pcep_event *event);
+const char *format_pcep_message(struct pcep_message *msg);
+const char *format_yang_dnode(struct lyd_node *dnode);
+
+#endif // _PATH_PCEP_DEBUG_H_
diff --git a/pathd/path_pcep_lib.c b/pathd/path_pcep_lib.c
new file mode 100644 (file)
index 0000000..bb6bfb1
--- /dev/null
@@ -0,0 +1,1146 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#include <debug.h>
+#include <pcep_utils_counters.h>
+#include <pcep_timers.h>
+#include "pathd/path_errors.h"
+#include "pathd/path_memory.h"
+#include "pathd/path_pcep.h"
+#include "pathd/path_pcep_lib.h"
+#include "pathd/path_pcep_debug.h"
+#include "pathd/path_pcep_memory.h"
+
+#define CLASS_TYPE(CLASS, TYPE) (((CLASS) << 16) | (TYPE))
+#define DEFAULT_LSAP_SETUP_PRIO 4
+#define DEFAULT_LSAP_HOLDING_PRIO 4
+#define DEFAULT_LSAP_LOCAL_PRETECTION false
+
+/* pceplib logging callback */
+static int pceplib_logging_cb(int level, const char *fmt, va_list args);
+
+/* Socket callbacks */
+static int pcep_lib_pceplib_socket_read_cb(void *fpt, void **thread, int fd,
+                                          void *payload);
+static int pcep_lib_pceplib_socket_write_cb(void *fpt, void **thread, int fd,
+                                           void *payload);
+static int pcep_lib_socket_read_ready(struct thread *thread);
+static int pcep_lib_socket_write_ready(struct thread *thread);
+
+/* pceplib pcep_event callbacks */
+static void pcep_lib_pceplib_event_cb(void *fpt, pcep_event *event);
+
+/* pceplib pthread creation callback */
+static int pcep_lib_pthread_create_cb(pthread_t *pthread_id,
+                                     const pthread_attr_t *attr,
+                                     void *(*start_routine)(void *),
+                                     void *data, const char *thread_name);
+void *pcep_lib_pthread_start_passthrough(void *data);
+int pcep_lib_pthread_stop_cb(struct frr_pthread *, void **);
+
+/* Internal functions */
+static double_linked_list *pcep_lib_format_path(struct pcep_caps *caps,
+                                               struct path *path);
+static void pcep_lib_format_constraints(struct path *path,
+                                       double_linked_list *objs);
+static void pcep_lib_parse_open(struct pcep_caps *caps,
+                               struct pcep_object_open *open);
+static void
+pcep_lib_parse_open_pce_capability(struct pcep_caps *caps,
+                                  struct pcep_object_tlv_header *tlv_header);
+static void
+pcep_lib_parse_open_objfun_list(struct pcep_caps *caps,
+                               struct pcep_object_tlv_header *tlv_header);
+static void pcep_lib_parse_rp(struct path *path, struct pcep_object_rp *rp);
+static void pcep_lib_parse_srp(struct path *path, struct pcep_object_srp *srp);
+static void pcep_lib_parse_lsp(struct path *path, struct pcep_object_lsp *lsp);
+static void pcep_lib_parse_lspa(struct path *path,
+                               struct pcep_object_lspa *lspa);
+static void pcep_lib_parse_metric(struct path *path,
+                                 struct pcep_object_metric *obj);
+static void pcep_lib_parse_ero(struct path *path, struct pcep_object_ro *ero);
+static struct path_hop *pcep_lib_parse_ero_sr(struct path_hop *next,
+                                             struct pcep_ro_subobj_sr *sr);
+static struct counters_group *copy_counter_group(struct counters_group *from);
+static struct counters_subgroup *
+copy_counter_subgroup(struct counters_subgroup *from);
+static struct counter *copy_counter(struct counter *from);
+static void free_counter_group(struct counters_group *group);
+static void free_counter_subgroup(struct counters_subgroup *subgroup);
+static void free_counter(struct counter *counter);
+
+struct pcep_lib_pthread_passthrough_data {
+       void *(*start_routine)(void *data);
+       void *data;
+};
+
+/* ------------ API Functions ------------ */
+
+int pcep_lib_initialize(struct frr_pthread *fpt)
+{
+       PCEP_DEBUG("Initializing pceplib");
+
+       /* Register pceplib logging callback */
+       register_logger(pceplib_logging_cb);
+
+       /* Its ok that this object goes out of scope, as it
+        * wont be stored, and its values will be copied */
+       struct pceplib_infra_config infra = {
+               /* Memory infrastructure */
+               .pceplib_infra_mt = MTYPE_PCEPLIB_INFRA,
+               .pceplib_messages_mt = MTYPE_PCEPLIB_MESSAGES,
+               .malloc_func = (pceplib_malloc_func)qmalloc,
+               .calloc_func = (pceplib_calloc_func)qcalloc,
+               .realloc_func = (pceplib_realloc_func)qrealloc,
+               .strdup_func = (pceplib_strdup_func)qstrdup,
+               .free_func = (pceplib_free_func)qfree,
+               /* Timers infrastructure */
+               .external_infra_data = fpt,
+               .socket_read_func = pcep_lib_pceplib_socket_read_cb,
+               .socket_write_func = pcep_lib_pceplib_socket_write_cb,
+               /* PCEP events */
+               .pcep_event_func = pcep_lib_pceplib_event_cb,
+               /* PCEPlib pthread creation callback */
+               .pthread_create_func = pcep_lib_pthread_create_cb};
+       if (!initialize_pcc_infra(&infra)) {
+               flog_err(EC_PATH_PCEP_PCC_INIT, "failed to initialize pceplib");
+               return 1;
+       }
+
+       return 0;
+}
+
+void pcep_lib_finalize(void)
+{
+       PCEP_DEBUG("Finalizing pceplib");
+       if (!destroy_pcc()) {
+               flog_err(EC_PATH_PCEP_PCC_FINI, "failed to finalize pceplib");
+       }
+}
+
+
+pcep_session *
+pcep_lib_connect(struct ipaddr *src_addr, int src_port, struct ipaddr *dst_addr,
+                int dst_port, short msd,
+                const struct pcep_config_group_opts *pcep_options)
+{
+       pcep_configuration *config;
+       pcep_session *sess;
+
+       config = create_default_pcep_configuration();
+       config->dst_pcep_port = dst_port;
+       config->src_pcep_port = src_port;
+       if (IS_IPADDR_V6(src_addr)) {
+               config->is_src_ipv6 = true;
+               memcpy(&config->src_ip.src_ipv6, &src_addr->ipaddr_v6,
+                      sizeof(struct in6_addr));
+       } else {
+               config->is_src_ipv6 = false;
+               config->src_ip.src_ipv4 = src_addr->ipaddr_v4;
+       }
+
+       config->support_stateful_pce_lsp_update = true;
+       config->support_pce_lsp_instantiation = false;
+       config->support_include_db_version = false;
+       config->support_lsp_triggered_resync = false;
+       config->support_lsp_delta_sync = false;
+       config->support_pce_triggered_initial_sync = false;
+       config->support_sr_te_pst = true;
+       config->pcc_can_resolve_nai_to_sid = false;
+
+       config->max_sid_depth = msd;
+       config->pcep_msg_versioning->draft_ietf_pce_segment_routing_07 =
+               pcep_options->draft07;
+       config->keep_alive_seconds = pcep_options->keep_alive_seconds;
+       config->min_keep_alive_seconds = pcep_options->min_keep_alive_seconds;
+       config->max_keep_alive_seconds = pcep_options->max_keep_alive_seconds;
+       config->dead_timer_seconds = pcep_options->dead_timer_seconds;
+       config->min_dead_timer_seconds = pcep_options->min_dead_timer_seconds;
+       config->max_dead_timer_seconds = pcep_options->max_dead_timer_seconds;
+       config->request_time_seconds = pcep_options->pcep_request_time_seconds;
+       /* TODO when available in the pceplib, set it here
+        pcep_options->state_timeout_inteval_seconds;*/
+
+       if (pcep_options->tcp_md5_auth != NULL
+           && pcep_options->tcp_md5_auth[0] != '\0') {
+               config->is_tcp_auth_md5 = true;
+               strncpy(config->tcp_authentication_str,
+                       pcep_options->tcp_md5_auth, TCP_MD5SIG_MAXKEYLEN);
+       } else {
+               config->is_tcp_auth_md5 = false;
+       }
+
+       if (IS_IPADDR_V6(dst_addr)) {
+               sess = connect_pce_ipv6(config, &dst_addr->ipaddr_v6);
+       } else {
+               sess = connect_pce(config, &dst_addr->ipaddr_v4);
+       }
+       destroy_pcep_configuration(config);
+       return sess;
+}
+
+void pcep_lib_disconnect(pcep_session *sess)
+{
+       assert(sess != NULL);
+       disconnect_pce(sess);
+}
+
+/* Callback passed to pceplib to write to a socket.
+ * When the socket is ready to be written to,
+ * pcep_lib_socket_write_ready() will be called */
+
+int pcep_lib_pceplib_socket_write_cb(void *fpt, void **thread, int fd,
+                                    void *payload)
+{
+       return pcep_thread_socket_write(fpt, thread, fd, payload,
+                                       pcep_lib_socket_write_ready);
+}
+
+/* Callback passed to pceplib to read from a socket.
+ * When the socket is ready to be read from,
+ * pcep_lib_socket_read_ready() will be called */
+
+int pcep_lib_pceplib_socket_read_cb(void *fpt, void **thread, int fd,
+                                   void *payload)
+{
+       return pcep_thread_socket_read(fpt, thread, fd, payload,
+                                      pcep_lib_socket_read_ready);
+}
+
+/* Callbacks called by path_pcep_controller when a socket is ready to read/write
+ */
+
+int pcep_lib_socket_write_ready(struct thread *thread)
+{
+       struct pcep_ctrl_socket_data *data = THREAD_ARG(thread);
+       assert(data != NULL);
+
+       int retval = pceplib_external_socket_write(data->fd, data->payload);
+       XFREE(MTYPE_PCEP, data);
+
+       return retval;
+}
+
+int pcep_lib_socket_read_ready(struct thread *thread)
+{
+       struct pcep_ctrl_socket_data *data = THREAD_ARG(thread);
+       assert(data != NULL);
+
+       int retval = pceplib_external_socket_read(data->fd, data->payload);
+       XFREE(MTYPE_PCEP, data);
+
+       return retval;
+}
+
+/* Callback passed to pceplib when a pcep_event is ready */
+void pcep_lib_pceplib_event_cb(void *fpt, pcep_event *event)
+{
+       pcep_thread_send_ctrl_event(fpt, event, pcep_thread_pcep_event);
+}
+
+/* Wrapper function around the actual pceplib thread start function */
+void *pcep_lib_pthread_start_passthrough(void *data)
+{
+       struct frr_pthread *fpt = data;
+       struct pcep_lib_pthread_passthrough_data *passthrough_data = fpt->data;
+       void *start_routine_data = passthrough_data->data;
+       void *(*start_routine)(void *) = passthrough_data->start_routine;
+       XFREE(MTYPE_PCEP, passthrough_data);
+
+       if (start_routine != NULL) {
+               return start_routine(start_routine_data);
+       }
+
+       return NULL;
+}
+
+int pcep_lib_pthread_create_cb(pthread_t *thread_id, const pthread_attr_t *attr,
+                              void *(*start_routine)(void *), void *data,
+                              const char *thread_name)
+{
+       /* Since FRR calls the start_routine with a struct frr_pthread,
+        * we have to store the real data and callback in a passthrough
+        * and pass the actual data the start_routine needs */
+       struct pcep_lib_pthread_passthrough_data *passthrough_data = XMALLOC(
+               MTYPE_PCEP, sizeof(struct pcep_lib_pthread_passthrough_data));
+       passthrough_data->data = data;
+       passthrough_data->start_routine = start_routine;
+
+       struct frr_pthread_attr fpt_attr = {
+               .start = pcep_lib_pthread_start_passthrough,
+               .stop = pcep_lib_pthread_stop_cb};
+       struct frr_pthread *fpt =
+               frr_pthread_new(&fpt_attr, thread_name, "pcep_lib");
+       if (fpt == NULL) {
+               return 1;
+       }
+
+       fpt->data = passthrough_data;
+       int retval = frr_pthread_run(fpt, attr);
+       if (retval) {
+               return retval;
+       }
+
+       *thread_id = fpt->thread;
+
+       return 0;
+}
+
+int pcep_lib_pthread_stop_cb(struct frr_pthread *fpt, void **res)
+{
+       pcep_lib_finalize();
+       frr_pthread_destroy(fpt);
+
+       return 0;
+}
+
+struct pcep_message *pcep_lib_format_report(struct pcep_caps *caps,
+                                           struct path *path)
+{
+       double_linked_list *objs = pcep_lib_format_path(caps, path);
+       return pcep_msg_create_report(objs);
+}
+
+static struct pcep_object_rp *create_rp(uint32_t reqid)
+{
+       double_linked_list *rp_tlvs;
+       struct pcep_object_tlv_path_setup_type *setup_type_tlv;
+       struct pcep_object_rp *rp;
+
+       rp_tlvs = dll_initialize();
+       setup_type_tlv = pcep_tlv_create_path_setup_type(SR_TE_PST);
+       dll_append(rp_tlvs, setup_type_tlv);
+
+       rp = pcep_obj_create_rp(0, false, false, false, true, reqid, rp_tlvs);
+
+       return rp;
+}
+
+struct pcep_message *pcep_lib_format_request(struct pcep_caps *caps,
+                                            struct path *path)
+{
+       struct ipaddr *src = &path->pcc_addr;
+       struct ipaddr *dst = &path->nbkey.endpoint;
+       double_linked_list *objs;
+       struct pcep_object_rp *rp;
+       struct pcep_object_endpoints_ipv4 *endpoints_ipv4;
+       struct pcep_object_endpoints_ipv6 *endpoints_ipv6;
+       struct pcep_object_objective_function *of = NULL;
+       enum objfun_type objfun = OBJFUN_UNDEFINED;
+
+       assert(src->ipa_type == dst->ipa_type);
+
+       objs = dll_initialize();
+       rp = create_rp(path->req_id);
+       rp->header.flag_p = true;
+
+       pcep_lib_format_constraints(path, objs);
+
+       /* Objective Function */
+       if (path->has_pcc_objfun) {
+               objfun = path->pcc_objfun;
+       }
+
+       if (objfun != OBJFUN_UNDEFINED) {
+               of = pcep_obj_create_objective_function(objfun, NULL);
+               assert(of != NULL);
+               of->header.flag_p = path->enforce_pcc_objfun;
+               dll_append(objs, of);
+       }
+
+       if (IS_IPADDR_V6(src)) {
+               endpoints_ipv6 = pcep_obj_create_endpoint_ipv6(&src->ipaddr_v6,
+                                                              &dst->ipaddr_v6);
+               endpoints_ipv6->header.flag_p = true;
+               return pcep_msg_create_request_ipv6(rp, endpoints_ipv6, objs);
+       } else {
+               endpoints_ipv4 = pcep_obj_create_endpoint_ipv4(&src->ipaddr_v4,
+                                                              &dst->ipaddr_v4);
+               endpoints_ipv4->header.flag_p = true;
+               return pcep_msg_create_request(rp, endpoints_ipv4, objs);
+       }
+}
+
+struct pcep_message *pcep_lib_format_error(int error_type, int error_value)
+{
+       return pcep_msg_create_error(error_type, error_value);
+}
+
+struct pcep_message *pcep_lib_format_request_cancelled(uint32_t reqid)
+{
+       struct pcep_object_notify *notify;
+       double_linked_list *objs;
+       struct pcep_object_rp *rp;
+
+       notify = pcep_obj_create_notify(
+               PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED,
+               PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST);
+       objs = dll_initialize();
+       rp = create_rp(reqid);
+       dll_append(objs, rp);
+
+       return pcep_msg_create_notify(notify, objs);
+}
+
+struct path *pcep_lib_parse_path(struct pcep_message *msg)
+{
+       struct path *path;
+       double_linked_list *objs = msg->obj_list;
+       double_linked_list_node *node;
+
+       struct pcep_object_header *obj;
+       struct pcep_object_rp *rp = NULL;
+       struct pcep_object_srp *srp = NULL;
+       struct pcep_object_lsp *lsp = NULL;
+       struct pcep_object_lspa *lspa = NULL;
+       struct pcep_object_ro *ero = NULL;
+       struct pcep_object_metric *metric = NULL;
+       struct pcep_object_bandwidth *bandwidth = NULL;
+       struct pcep_object_objective_function *of = NULL;
+
+       path = pcep_new_path();
+
+       for (node = objs->head; node != NULL; node = node->next_node) {
+               obj = (struct pcep_object_header *)node->data;
+               switch (CLASS_TYPE(obj->object_class, obj->object_type)) {
+               case CLASS_TYPE(PCEP_OBJ_CLASS_RP, PCEP_OBJ_TYPE_RP):
+                       assert(rp == NULL);
+                       rp = (struct pcep_object_rp *)obj;
+                       pcep_lib_parse_rp(path, rp);
+                       break;
+               case CLASS_TYPE(PCEP_OBJ_CLASS_SRP, PCEP_OBJ_TYPE_SRP):
+                       assert(srp == NULL);
+                       srp = (struct pcep_object_srp *)obj;
+                       pcep_lib_parse_srp(path, srp);
+                       break;
+               case CLASS_TYPE(PCEP_OBJ_CLASS_LSP, PCEP_OBJ_TYPE_LSP):
+                       /* Only support single LSP per message */
+                       assert(lsp == NULL);
+                       lsp = (struct pcep_object_lsp *)obj;
+                       pcep_lib_parse_lsp(path, lsp);
+                       break;
+               case CLASS_TYPE(PCEP_OBJ_CLASS_LSPA, PCEP_OBJ_TYPE_LSPA):
+                       assert(lspa == NULL);
+                       lspa = (struct pcep_object_lspa *)obj;
+                       pcep_lib_parse_lspa(path, lspa);
+                       break;
+               case CLASS_TYPE(PCEP_OBJ_CLASS_ERO, PCEP_OBJ_TYPE_ERO):
+                       /* Only support single ERO per message */
+                       assert(ero == NULL);
+                       ero = (struct pcep_object_ro *)obj;
+                       pcep_lib_parse_ero(path, ero);
+                       break;
+               case CLASS_TYPE(PCEP_OBJ_CLASS_METRIC, PCEP_OBJ_TYPE_METRIC):
+                       metric = (struct pcep_object_metric *)obj;
+                       pcep_lib_parse_metric(path, metric);
+                       break;
+               case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH,
+                               PCEP_OBJ_TYPE_BANDWIDTH_REQ):
+               case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH,
+                               PCEP_OBJ_TYPE_BANDWIDTH_CISCO):
+                       bandwidth = (struct pcep_object_bandwidth *)obj;
+                       path->has_bandwidth = true;
+                       path->bandwidth = bandwidth->bandwidth;
+                       break;
+               case CLASS_TYPE(PCEP_OBJ_CLASS_NOPATH, PCEP_OBJ_TYPE_NOPATH):
+                       path->no_path = true;
+                       break;
+               case CLASS_TYPE(PCEP_OBJ_CLASS_OF, PCEP_OBJ_TYPE_OF):
+                       of = (struct pcep_object_objective_function *)obj;
+                       path->has_pce_objfun = true;
+                       path->pce_objfun = of->of_code;
+                       break;
+               default:
+                       flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT,
+                                 "Unexpected PCEP object %s (%u) / %s (%u)",
+                                 pcep_object_class_name(obj->object_class),
+                                 obj->object_class,
+                                 pcep_object_type_name(obj->object_class,
+                                                       obj->object_type),
+                                 obj->object_type);
+                       break;
+               }
+       }
+
+       return path;
+}
+
+void pcep_lib_parse_capabilities(struct pcep_message *msg,
+                                struct pcep_caps *caps)
+{
+       double_linked_list *objs = msg->obj_list;
+       double_linked_list_node *node;
+
+       struct pcep_object_header *obj;
+       struct pcep_object_open *open = NULL;
+
+       for (node = objs->head; node != NULL; node = node->next_node) {
+               obj = (struct pcep_object_header *)node->data;
+               switch (CLASS_TYPE(obj->object_class, obj->object_type)) {
+               case CLASS_TYPE(PCEP_OBJ_CLASS_OPEN, PCEP_OBJ_TYPE_OPEN):
+                       assert(open == NULL);
+                       open = (struct pcep_object_open *)obj;
+                       pcep_lib_parse_open(caps, open);
+                       break;
+               default:
+                       flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT,
+                                 "Unexpected PCEP object %s (%u) / %s (%u)",
+                                 pcep_object_class_name(obj->object_class),
+                                 obj->object_class,
+                                 pcep_object_type_name(obj->object_class,
+                                                       obj->object_type),
+                                 obj->object_type);
+                       break;
+               }
+       }
+}
+
+struct counters_group *pcep_lib_copy_counters(pcep_session *sess)
+{
+       if (!sess || !sess->pcep_session_counters) {
+               return NULL;
+       }
+
+       return copy_counter_group(sess->pcep_session_counters);
+}
+
+void pcep_lib_free_counters(struct counters_group *counters)
+{
+       free_counter_group(counters);
+}
+
+pcep_session *pcep_lib_copy_pcep_session(pcep_session *sess)
+{
+       if (!sess) {
+               return NULL;
+       }
+
+       pcep_session *copy;
+       copy = XCALLOC(MTYPE_PCEP, sizeof(*copy));
+       memcpy(copy, sess, sizeof(*copy));
+       /* These fields should not be accessed */
+       copy->num_unknown_messages_time_queue = NULL;
+       copy->socket_comm_session = NULL;
+       copy->pcep_session_counters = NULL;
+
+       return copy;
+}
+
+/* ------------ pceplib logging callback ------------ */
+
+int pceplib_logging_cb(int priority, const char *fmt, va_list args)
+{
+       char buffer[1024];
+       vsnprintf(buffer, sizeof(buffer), fmt, args);
+       PCEP_DEBUG_PCEPLIB(priority, "pceplib: %s", buffer);
+       return 0;
+}
+
+/* ------------ Internal Functions ------------ */
+
+double_linked_list *pcep_lib_format_path(struct pcep_caps *caps,
+                                        struct path *path)
+{
+       struct in_addr addr_null;
+       double_linked_list *objs, *srp_tlvs, *lsp_tlvs, *ero_objs;
+       struct pcep_object_tlv_header *tlv;
+       struct pcep_object_ro_subobj *ero_obj;
+       struct pcep_object_srp *srp;
+       struct pcep_object_lsp *lsp;
+       struct pcep_object_ro *ero;
+       uint32_t encoded_binding_sid;
+       char binding_sid_lsp_tlv_data[6];
+
+       memset(&addr_null, 0, sizeof(addr_null));
+
+       objs = dll_initialize();
+
+       if (path->plsp_id != 0) {
+               /* SRP object */
+               srp_tlvs = dll_initialize();
+               tlv = (struct pcep_object_tlv_header *)
+                       pcep_tlv_create_path_setup_type(SR_TE_PST);
+               assert(tlv != NULL);
+               dll_append(srp_tlvs, tlv);
+               srp = pcep_obj_create_srp(path->do_remove, path->srp_id,
+                                         srp_tlvs);
+               assert(srp != NULL);
+               srp->header.flag_p = true;
+               dll_append(objs, srp);
+       }
+
+       /* LSP object */
+       lsp_tlvs = dll_initialize();
+
+       if (path->plsp_id == 0 || IS_IPADDR_NONE(&path->nbkey.endpoint)
+           || IS_IPADDR_NONE(&path->pcc_addr)) {
+               tlv = (struct pcep_object_tlv_header *)
+                       pcep_tlv_create_ipv4_lsp_identifiers(
+                               &addr_null, &addr_null, 0, 0, &addr_null);
+       } else {
+               assert(path->pcc_addr.ipa_type
+                      == path->nbkey.endpoint.ipa_type);
+               if (IS_IPADDR_V4(&path->pcc_addr)) {
+                       tlv = (struct pcep_object_tlv_header *)
+                               pcep_tlv_create_ipv4_lsp_identifiers(
+                                       &path->pcc_addr.ipaddr_v4,
+                                       &path->nbkey.endpoint.ipaddr_v4, 0, 0,
+                                       &path->pcc_addr.ipaddr_v4);
+               } else {
+                       tlv = (struct pcep_object_tlv_header *)
+                               pcep_tlv_create_ipv6_lsp_identifiers(
+                                       &path->pcc_addr.ipaddr_v6,
+                                       &path->nbkey.endpoint.ipaddr_v6, 0, 0,
+                                       &path->pcc_addr.ipaddr_v6);
+               }
+       }
+       assert(tlv != NULL);
+       dll_append(lsp_tlvs, tlv);
+       if (path->name != NULL) {
+               tlv = (struct pcep_object_tlv_header *)
+                       /*FIXME: Remove the typecasty when pceplib is changed
+                       to take a const char* */
+                       pcep_tlv_create_symbolic_path_name((char *)path->name,
+                                                          strlen(path->name));
+               assert(tlv != NULL);
+               dll_append(lsp_tlvs, tlv);
+       }
+       if ((path->plsp_id != 0) && (path->binding_sid != MPLS_LABEL_NONE)) {
+               memset(binding_sid_lsp_tlv_data, 0, 2);
+               encoded_binding_sid = htonl(path->binding_sid << 12);
+               memcpy(binding_sid_lsp_tlv_data + 2, &encoded_binding_sid, 4);
+               tlv = (struct pcep_object_tlv_header *)
+                       pcep_tlv_create_tlv_arbitrary(
+                               binding_sid_lsp_tlv_data,
+                               sizeof(binding_sid_lsp_tlv_data), 65505);
+               assert(tlv != NULL);
+               dll_append(lsp_tlvs, tlv);
+       }
+       lsp = pcep_obj_create_lsp(
+               path->plsp_id, path->status, path->was_created /* C Flag */,
+               path->go_active /* A Flag */, path->was_removed /* R Flag */,
+               path->is_synching /* S Flag */, path->is_delegated /* D Flag */,
+               lsp_tlvs);
+       assert(lsp != NULL);
+       lsp->header.flag_p = true;
+       dll_append(objs, lsp);
+       /*   ERO object */
+       ero_objs = dll_initialize();
+       for (struct path_hop *hop = path->first_hop; hop != NULL;
+            hop = hop->next) {
+               uint32_t sid;
+
+               /* Only supporting MPLS hops with both sid and nai */
+               assert(hop->is_mpls);
+               assert(hop->has_sid);
+
+               if (hop->has_attribs) {
+                       sid = ENCODE_SR_ERO_SID(hop->sid.mpls.label,
+                                               hop->sid.mpls.traffic_class,
+                                               hop->sid.mpls.is_bottom,
+                                               hop->sid.mpls.ttl);
+               } else {
+                       sid = ENCODE_SR_ERO_SID(hop->sid.mpls.label, 0, 0, 0);
+               }
+
+               ero_obj = NULL;
+               if (hop->has_nai) {
+                       assert(hop->nai.type != PCEP_SR_SUBOBJ_NAI_ABSENT);
+                       assert(hop->nai.type
+                              != PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY);
+                       assert(hop->nai.type != PCEP_SR_SUBOBJ_NAI_UNKNOWN);
+                       switch (hop->nai.type) {
+                       case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
+                               ero_obj = (struct pcep_object_ro_subobj *)
+                                       pcep_obj_create_ro_subobj_sr_ipv4_node(
+                                               hop->is_loose, !hop->has_sid,
+                                               hop->has_attribs, /* C Flag */
+                                               hop->is_mpls,     /* M Flag */
+                                               sid,
+                                               &hop->nai.local_addr.ipaddr_v4);
+                               break;
+                       case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
+                               ero_obj = (struct pcep_object_ro_subobj *)
+                                       pcep_obj_create_ro_subobj_sr_ipv6_node(
+                                               hop->is_loose, !hop->has_sid,
+                                               hop->has_attribs, /* C Flag */
+                                               hop->is_mpls,     /* M Flag */
+                                               sid,
+                                               &hop->nai.local_addr.ipaddr_v6);
+                               break;
+                       case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
+                               ero_obj = (struct pcep_object_ro_subobj *)
+                                       pcep_obj_create_ro_subobj_sr_ipv4_adj(
+                                               hop->is_loose, !hop->has_sid,
+                                               hop->has_attribs, /* C Flag */
+                                               hop->is_mpls,     /* M Flag */
+                                               sid,
+                                               &hop->nai.local_addr.ipaddr_v4,
+                                               &hop->nai.remote_addr
+                                                        .ipaddr_v4);
+                               break;
+                       case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
+                               ero_obj = (struct pcep_object_ro_subobj *)
+                                       pcep_obj_create_ro_subobj_sr_ipv6_adj(
+                                               hop->is_loose, !hop->has_sid,
+                                               hop->has_attribs, /* C Flag */
+                                               hop->is_mpls,     /* M Flag */
+                                               sid,
+                                               &hop->nai.local_addr.ipaddr_v6,
+                                               &hop->nai.remote_addr
+                                                        .ipaddr_v6);
+                               break;
+                       case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
+                               ero_obj = (struct pcep_object_ro_subobj *)
+                                       pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
+                                               hop->is_loose, !hop->has_sid,
+                                               hop->has_attribs, /* C Flag */
+                                               hop->is_mpls,     /* M Flag */
+                                               sid,
+                                               hop->nai.local_addr.ipaddr_v4
+                                                       .s_addr,
+                                               hop->nai.local_iface,
+                                               hop->nai.remote_addr.ipaddr_v4
+                                                       .s_addr,
+                                               hop->nai.remote_iface);
+                               break;
+                       default:
+                               break;
+                       }
+               }
+               if (ero_obj == NULL) {
+                       ero_obj = (struct pcep_object_ro_subobj *)
+                               pcep_obj_create_ro_subobj_sr_nonai(
+                                       hop->is_loose, sid,
+                                       hop->has_attribs, /* C Flag */
+                                       hop->is_mpls);    /* M Flag */
+               }
+               dll_append(ero_objs, ero_obj);
+       }
+       ero = pcep_obj_create_ero(ero_objs);
+       assert(ero != NULL);
+       ero->header.flag_p = true;
+       dll_append(objs, ero);
+
+       if (path->plsp_id == 0) {
+               return objs;
+       }
+
+       pcep_lib_format_constraints(path, objs);
+
+       return objs;
+}
+
+void pcep_lib_format_constraints(struct path *path, double_linked_list *objs)
+{
+       struct pcep_object_metric *metric;
+       struct pcep_object_bandwidth *bandwidth;
+       struct pcep_object_lspa *lspa;
+
+       /* LSPA object */
+       if (path->has_affinity_filters) {
+               lspa = pcep_obj_create_lspa(
+                       path->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY - 1],
+                       path->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY - 1],
+                       path->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL - 1],
+                       DEFAULT_LSAP_SETUP_PRIO, DEFAULT_LSAP_HOLDING_PRIO,
+                       DEFAULT_LSAP_LOCAL_PRETECTION);
+               assert(lspa != NULL);
+               lspa->header.flag_p = true;
+               dll_append(objs, lspa);
+       }
+
+       /* Bandwidth Objects */
+       if (path->has_bandwidth) {
+               /* Requested Bandwidth */
+               bandwidth = pcep_obj_create_bandwidth(path->bandwidth);
+               assert(bandwidth != NULL);
+               bandwidth->header.flag_p = path->enforce_bandwidth;
+               dll_append(objs, bandwidth);
+       }
+
+       /* Metric Objects */
+       for (struct path_metric *m = path->first_metric; m != NULL;
+            m = m->next) {
+               metric = pcep_obj_create_metric(m->type, m->is_bound,
+                                               m->is_computed, m->value);
+               assert(metric != NULL);
+               metric->header.flag_p = m->enforce;
+               dll_append(objs, metric);
+       }
+}
+
+void pcep_lib_parse_open(struct pcep_caps *caps, struct pcep_object_open *open)
+{
+       double_linked_list *tlvs = open->header.tlv_list;
+       double_linked_list_node *node;
+       struct pcep_object_tlv_header *tlv_header;
+
+       caps->is_stateful = false;
+       caps->supported_ofs_are_known = false;
+       caps->supported_ofs = 0;
+
+       for (node = tlvs->head; node != NULL; node = node->next_node) {
+               tlv_header = (struct pcep_object_tlv_header *)node->data;
+               switch (tlv_header->type) {
+               case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY:
+                       pcep_lib_parse_open_pce_capability(caps, tlv_header);
+                       break;
+               case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY:
+                       break;
+               case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST:
+                       pcep_lib_parse_open_objfun_list(caps, tlv_header);
+                       break;
+               default:
+                       flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
+                                 "Unexpected OPEN's TLV %s (%u)",
+                                 pcep_tlv_type_name(tlv_header->type),
+                                 tlv_header->type);
+                       break;
+               }
+       }
+}
+
+void pcep_lib_parse_open_pce_capability(
+       struct pcep_caps *caps, struct pcep_object_tlv_header *tlv_header)
+{
+       struct pcep_object_tlv_stateful_pce_capability *tlv;
+       tlv = (struct pcep_object_tlv_stateful_pce_capability *)tlv_header;
+       caps->is_stateful = tlv->flag_u_lsp_update_capability;
+}
+
+void pcep_lib_parse_open_objfun_list(struct pcep_caps *caps,
+                                    struct pcep_object_tlv_header *tlv_header)
+{
+       double_linked_list_node *node;
+       struct pcep_object_tlv_of_list *tlv;
+       tlv = (struct pcep_object_tlv_of_list *)tlv_header;
+       uint16_t of_code;
+       caps->supported_ofs_are_known = true;
+       for (node = tlv->of_list->head; node != NULL; node = node->next_node) {
+               of_code = *(uint16_t *)node->data;
+               if (of_code >= 32) {
+                       zlog_warn(
+                               "Ignoring unexpected objective function with code %u",
+                               of_code);
+                       continue;
+               }
+               SET_FLAG(caps->supported_ofs, of_code);
+       }
+}
+
+void pcep_lib_parse_rp(struct path *path, struct pcep_object_rp *rp)
+{
+       double_linked_list *tlvs = rp->header.tlv_list;
+       double_linked_list_node *node;
+       struct pcep_object_tlv_header *tlv;
+
+       /* We ignore the other flags and priority for now */
+       path->req_id = rp->request_id;
+       path->has_pce_objfun = false;
+       path->pce_objfun = OBJFUN_UNDEFINED;
+
+       for (node = tlvs->head; node != NULL; node = node->next_node) {
+               tlv = (struct pcep_object_tlv_header *)node->data;
+               switch (tlv->type) {
+               case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE:
+                       // TODO: enforce the path setup type is SR_TE_PST
+                       break;
+               default:
+                       flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
+                                 "Unexpected RP's TLV %s (%u)",
+                                 pcep_tlv_type_name(tlv->type), tlv->type);
+                       break;
+               }
+       }
+}
+
+void pcep_lib_parse_srp(struct path *path, struct pcep_object_srp *srp)
+{
+       double_linked_list *tlvs = srp->header.tlv_list;
+       double_linked_list_node *node;
+       struct pcep_object_tlv_header *tlv;
+
+       path->do_remove = srp->flag_lsp_remove;
+       path->srp_id = srp->srp_id_number;
+
+       for (node = tlvs->head; node != NULL; node = node->next_node) {
+               tlv = (struct pcep_object_tlv_header *)node->data;
+               switch (tlv->type) {
+               case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE:
+                       // TODO: enforce the path setup type is SR_TE_PST
+                       break;
+               default:
+                       flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
+                                 "Unexpected SRP's TLV %s (%u)",
+                                 pcep_tlv_type_name(tlv->type), tlv->type);
+                       break;
+               }
+       }
+}
+
+void pcep_lib_parse_lsp(struct path *path, struct pcep_object_lsp *lsp)
+{
+       double_linked_list *tlvs = lsp->header.tlv_list;
+       double_linked_list_node *node;
+       struct pcep_object_tlv_header *tlv;
+
+       path->plsp_id = lsp->plsp_id;
+       path->status = lsp->operational_status;
+       path->go_active = lsp->flag_a;
+       path->was_created = lsp->flag_c;
+       path->was_removed = lsp->flag_r;
+       path->is_synching = lsp->flag_s;
+       path->is_delegated = lsp->flag_d;
+
+       if (tlvs == NULL)
+               return;
+
+       for (node = tlvs->head; node != NULL; node = node->next_node) {
+               tlv = (struct pcep_object_tlv_header *)node->data;
+               switch (tlv->type) {
+               default:
+                       flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
+                                 "Unexpected LSP TLV %s (%u)",
+                                 pcep_tlv_type_name(tlv->type), tlv->type);
+                       break;
+               }
+       }
+}
+
+void pcep_lib_parse_lspa(struct path *path, struct pcep_object_lspa *lspa)
+{
+       path->has_affinity_filters = true;
+       path->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY - 1] =
+               lspa->lspa_exclude_any;
+       path->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY - 1] =
+               lspa->lspa_include_any;
+       path->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL - 1] =
+               lspa->lspa_include_all;
+}
+
+void pcep_lib_parse_metric(struct path *path, struct pcep_object_metric *obj)
+{
+       struct path_metric *metric;
+
+       metric = pcep_new_metric();
+       metric->type = obj->type;
+       metric->is_bound = obj->flag_b;
+       metric->is_computed = obj->flag_c;
+       metric->value = obj->value;
+       metric->next = path->first_metric;
+       path->first_metric = metric;
+}
+
+void pcep_lib_parse_ero(struct path *path, struct pcep_object_ro *ero)
+{
+       struct path_hop *hop = NULL;
+       double_linked_list *objs = ero->sub_objects;
+       double_linked_list_node *node;
+       struct pcep_object_ro_subobj *obj;
+
+       for (node = objs->tail; node != NULL; node = node->prev_node) {
+               obj = (struct pcep_object_ro_subobj *)node->data;
+               switch (obj->ro_subobj_type) {
+               case RO_SUBOBJ_TYPE_SR:
+                       hop = pcep_lib_parse_ero_sr(
+                               hop, (struct pcep_ro_subobj_sr *)obj);
+                       break;
+               default:
+                       flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_ERO_SUBOBJ,
+                                 "Unexpected ERO sub-object %s (%u)",
+                                 pcep_ro_type_name(obj->ro_subobj_type),
+                                 obj->ro_subobj_type);
+                       break;
+               }
+       }
+
+       path->first_hop = hop;
+}
+
+struct path_hop *pcep_lib_parse_ero_sr(struct path_hop *next,
+                                      struct pcep_ro_subobj_sr *sr)
+{
+       struct path_hop *hop = NULL;
+       union sid sid;
+
+       /* Only support IPv4 node with SID */
+       assert(!sr->flag_s);
+
+       if (sr->flag_m) {
+               sid.mpls = (struct sid_mpls){
+                       .label = GET_SR_ERO_SID_LABEL(sr->sid),
+                       .traffic_class = GET_SR_ERO_SID_TC(sr->sid),
+                       .is_bottom = GET_SR_ERO_SID_S(sr->sid),
+                       .ttl = GET_SR_ERO_SID_TTL(sr->sid)};
+       } else {
+               sid.value = sr->sid;
+       }
+
+       hop = pcep_new_hop();
+       *hop = (struct path_hop){.next = next,
+                                .is_loose =
+                                        sr->ro_subobj.flag_subobj_loose_hop,
+                                .has_sid = !sr->flag_s,
+                                .is_mpls = sr->flag_m,
+                                .has_attribs = sr->flag_c,
+                                .sid = sid,
+                                .has_nai = !sr->flag_f,
+                                .nai = {.type = sr->nai_type}};
+
+       if (!sr->flag_f) {
+               assert(sr->nai_list != NULL);
+               double_linked_list_node *n = sr->nai_list->head;
+               assert(n != NULL);
+               assert(n->data != NULL);
+               switch (sr->nai_type) {
+               case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
+                       hop->nai.local_addr.ipa_type = IPADDR_V4;
+                       memcpy(&hop->nai.local_addr.ipaddr_v4, n->data,
+                              sizeof(struct in_addr));
+                       break;
+               case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
+                       hop->nai.local_addr.ipa_type = IPADDR_V6;
+                       memcpy(&hop->nai.local_addr.ipaddr_v6, n->data,
+                              sizeof(struct in6_addr));
+                       break;
+               case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
+                       hop->nai.local_addr.ipa_type = IPADDR_V4;
+                       memcpy(&hop->nai.local_addr.ipaddr_v4, n->data,
+                              sizeof(struct in_addr));
+                       n = n->next_node;
+                       assert(n != NULL);
+                       assert(n->data != NULL);
+                       hop->nai.remote_addr.ipa_type = IPADDR_V4;
+                       memcpy(&hop->nai.remote_addr.ipaddr_v4, n->data,
+                              sizeof(struct in_addr));
+                       break;
+               case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
+                       hop->nai.local_addr.ipa_type = IPADDR_V6;
+                       memcpy(&hop->nai.local_addr.ipaddr_v6, n->data,
+                              sizeof(struct in6_addr));
+                       n = n->next_node;
+                       assert(n != NULL);
+                       assert(n->data != NULL);
+                       hop->nai.remote_addr.ipa_type = IPADDR_V6;
+                       memcpy(&hop->nai.remote_addr.ipaddr_v6, n->data,
+                              sizeof(struct in6_addr));
+                       break;
+               case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
+                       hop->nai.local_addr.ipa_type = IPADDR_V4;
+                       memcpy(&hop->nai.local_addr.ipaddr_v4, n->data,
+                              sizeof(struct in_addr));
+                       n = n->next_node;
+                       assert(n != NULL);
+                       assert(n->data != NULL);
+                       hop->nai.local_iface = *(uint32_t *)n->data;
+                       n = n->next_node;
+                       assert(n != NULL);
+                       assert(n->data != NULL);
+                       hop->nai.remote_addr.ipa_type = IPADDR_V4;
+                       memcpy(&hop->nai.remote_addr.ipaddr_v4, n->data,
+                              sizeof(struct in_addr));
+                       n = n->next_node;
+                       assert(n != NULL);
+                       assert(n->data != NULL);
+                       hop->nai.remote_iface = *(uint32_t *)n->data;
+                       break;
+               default:
+                       hop->has_nai = false;
+                       flog_warn(EC_PATH_PCEP_UNEXPECTED_SR_NAI,
+                                 "Unexpected SR segment NAI type %s (%u)",
+                                 pcep_nai_type_name(sr->nai_type),
+                                 sr->nai_type);
+                       break;
+               }
+       }
+
+       return hop;
+}
+
+struct counters_group *copy_counter_group(struct counters_group *from)
+{
+       int size, i;
+       struct counters_group *result;
+       if (from == NULL)
+               return NULL;
+       assert(from->max_subgroups >= from->num_subgroups);
+       result = XCALLOC(MTYPE_PCEP, sizeof(*result));
+       memcpy(result, from, sizeof(*result));
+       size = sizeof(struct counters_subgroup *) * (from->max_subgroups + 1);
+       result->subgroups = XCALLOC(MTYPE_PCEP, size);
+       for (i = 0; i <= from->max_subgroups; i++)
+               result->subgroups[i] =
+                       copy_counter_subgroup(from->subgroups[i]);
+       return result;
+}
+
+struct counters_subgroup *copy_counter_subgroup(struct counters_subgroup *from)
+{
+       int size, i;
+       struct counters_subgroup *result;
+       if (from == NULL)
+               return NULL;
+       assert(from->max_counters >= from->num_counters);
+       result = XCALLOC(MTYPE_PCEP, sizeof(*result));
+       memcpy(result, from, sizeof(*result));
+       size = sizeof(struct counter *) * (from->max_counters + 1);
+       result->counters = XCALLOC(MTYPE_PCEP, size);
+       for (i = 0; i <= from->max_counters; i++)
+               result->counters[i] = copy_counter(from->counters[i]);
+       return result;
+}
+
+struct counter *copy_counter(struct counter *from)
+{
+       struct counter *result;
+       if (from == NULL)
+               return NULL;
+       result = XCALLOC(MTYPE_PCEP, sizeof(*result));
+       memcpy(result, from, sizeof(*result));
+       return result;
+}
+
+void free_counter_group(struct counters_group *group)
+{
+       int i;
+       if (group == NULL)
+               return;
+       for (i = 0; i <= group->max_subgroups; i++)
+               free_counter_subgroup(group->subgroups[i]);
+       XFREE(MTYPE_PCEP, group->subgroups);
+       XFREE(MTYPE_PCEP, group);
+}
+
+void free_counter_subgroup(struct counters_subgroup *subgroup)
+{
+       int i;
+       if (subgroup == NULL)
+               return;
+       for (i = 0; i <= subgroup->max_counters; i++)
+               free_counter(subgroup->counters[i]);
+       XFREE(MTYPE_PCEP, subgroup->counters);
+       XFREE(MTYPE_PCEP, subgroup);
+}
+
+void free_counter(struct counter *counter)
+{
+       if (counter == NULL)
+               return;
+       XFREE(MTYPE_PCEP, counter);
+}
diff --git a/pathd/path_pcep_lib.h b/pathd/path_pcep_lib.h
new file mode 100644 (file)
index 0000000..3bea284
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#ifndef _PATH_PCEP_LIB_H_
+#define _PATH_PCEP_LIB_H_
+
+#include <stdbool.h>
+#include <pcep_pcc_api.h>
+#include "frr_pthread.h"
+#include "pathd/path_pcep.h"
+
+int pcep_lib_initialize(struct frr_pthread *fpt);
+void pcep_lib_finalize(void);
+pcep_session *
+pcep_lib_connect(struct ipaddr *src_addr, int src_port, struct ipaddr *dst_addr,
+                int dst_port, short msd,
+                const struct pcep_config_group_opts *pcep_options);
+void pcep_lib_disconnect(pcep_session *sess);
+struct pcep_message *pcep_lib_format_report(struct pcep_caps *caps,
+                                           struct path *path);
+struct pcep_message *pcep_lib_format_request(struct pcep_caps *caps,
+                                            struct path *path);
+struct pcep_message *pcep_lib_format_request_cancelled(uint32_t reqid);
+
+struct pcep_message *pcep_lib_format_error(int error_type, int error_value);
+struct path *pcep_lib_parse_path(struct pcep_message *msg);
+void pcep_lib_parse_capabilities(struct pcep_message *msg,
+                                struct pcep_caps *caps);
+struct counters_group *pcep_lib_copy_counters(pcep_session *sess);
+void pcep_lib_free_counters(struct counters_group *counters);
+pcep_session *pcep_lib_copy_pcep_session(pcep_session *sess);
+
+#endif // _PATH_PCEP_LIB_H_
diff --git a/pathd/path_pcep_memory.c b/pathd/path_pcep_memory.c
new file mode 100644 (file)
index 0000000..8f60809
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#include <zebra.h>
+
+#include <memory.h>
+
+#include "pathd/path_pcep_memory.h"
+
+DEFINE_MTYPE(PATHD, PCEP, "PCEP module")
+DEFINE_MTYPE(PATHD, PCEPLIB_INFRA, "PCEPlib Infrastructure")
+DEFINE_MTYPE(PATHD, PCEPLIB_MESSAGES, "PCEPlib PCEP Messages")
diff --git a/pathd/path_pcep_memory.h b/pathd/path_pcep_memory.h
new file mode 100644 (file)
index 0000000..05c5e2d
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#ifndef _FRR_PATH_PCEP_MEMORY_H_
+#define _FRR_PATH_PCEP_MEMORY_H_
+
+#include "pathd/path_memory.h"
+
+DECLARE_MTYPE(PCEP)
+DECLARE_MTYPE(PCEPLIB_INFRA)
+DECLARE_MTYPE(PCEPLIB_MESSAGES)
+
+#endif /* _FRR_PATH_PCEP_MEMORY_H_ */
diff --git a/pathd/path_pcep_pcc.c b/pathd/path_pcep_pcc.c
new file mode 100644 (file)
index 0000000..c1f60ed
--- /dev/null
@@ -0,0 +1,1818 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+/* TODOS AND KNOWN ISSUES:
+       - Delete mapping from NB keys to PLSPID when an LSP is deleted either
+         by the PCE or by NB.
+       - Revert the hacks to work around ODL requiring a report with
+         operational status DOWN when an LSP is activated.
+       - Enforce only the PCE a policy has been delegated to can update it.
+       - If the router-id is used because the PCC IP is not specified
+         (either IPv4 or IPv6), the connection to the PCE is not reset
+         when the router-id changes.
+*/
+
+#include <zebra.h>
+
+#include "log.h"
+#include "command.h"
+#include "libfrr.h"
+#include "printfrr.h"
+#include "version.h"
+#include "northbound.h"
+#include "frr_pthread.h"
+#include "jhash.h"
+
+#include "pathd/pathd.h"
+#include "pathd/path_zebra.h"
+#include "pathd/path_errors.h"
+#include "pathd/path_pcep_memory.h"
+#include "pathd/path_pcep.h"
+#include "pathd/path_pcep_controller.h"
+#include "pathd/path_pcep_lib.h"
+#include "pathd/path_pcep_config.h"
+#include "pathd/path_pcep_debug.h"
+
+
+/* The number of time we will skip connecting if we are missing the PCC
+ * address for an inet family different from the selected transport one*/
+#define OTHER_FAMILY_MAX_RETRIES 4
+#define MAX_ERROR_MSG_SIZE 256
+#define MAX_COMPREQ_TRIES 3
+
+
+/* PCEP Event Handler */
+static void handle_pcep_open(struct ctrl_state *ctrl_state,
+                            struct pcc_state *pcc_state,
+                            struct pcep_message *msg);
+static void handle_pcep_message(struct ctrl_state *ctrl_state,
+                               struct pcc_state *pcc_state,
+                               struct pcep_message *msg);
+static void handle_pcep_lsp_update(struct ctrl_state *ctrl_state,
+                                  struct pcc_state *pcc_state,
+                                  struct pcep_message *msg);
+static void handle_pcep_lsp_initiate(struct ctrl_state *ctrl_state,
+                                    struct pcc_state *pcc_state,
+                                    struct pcep_message *msg);
+static void handle_pcep_comp_reply(struct ctrl_state *ctrl_state,
+                                  struct pcc_state *pcc_state,
+                                  struct pcep_message *msg);
+
+/* Internal Functions */
+static const char *ipaddr_type_name(struct ipaddr *addr);
+static bool filter_path(struct pcc_state *pcc_state, struct path *path);
+static void select_pcc_addresses(struct pcc_state *pcc_state);
+static void select_transport_address(struct pcc_state *pcc_state);
+static void update_tag(struct pcc_state *pcc_state);
+static void update_originator(struct pcc_state *pcc_state);
+static void schedule_reconnect(struct ctrl_state *ctrl_state,
+                              struct pcc_state *pcc_state);
+static void schedule_session_timeout(struct ctrl_state *ctrl_state,
+                                    struct pcc_state *pcc_state);
+static void cancel_session_timeout(struct ctrl_state *ctrl_state,
+                                  struct pcc_state *pcc_state);
+static void send_pcep_message(struct pcc_state *pcc_state,
+                             struct pcep_message *msg);
+static void send_pcep_error(struct pcc_state *pcc_state,
+                           enum pcep_error_type error_type,
+                           enum pcep_error_value error_value);
+static void send_report(struct pcc_state *pcc_state, struct path *path);
+static void send_comp_request(struct ctrl_state *ctrl_state,
+                             struct pcc_state *pcc_state,
+                             struct req_entry *req);
+static void cancel_comp_requests(struct ctrl_state *ctrl_state,
+                                struct pcc_state *pcc_state);
+static void cancel_comp_request(struct ctrl_state *ctrl_state,
+                               struct pcc_state *pcc_state,
+                               struct req_entry *req);
+static void specialize_outgoing_path(struct pcc_state *pcc_state,
+                                    struct path *path);
+static void specialize_incoming_path(struct pcc_state *pcc_state,
+                                    struct path *path);
+static bool validate_incoming_path(struct pcc_state *pcc_state,
+                                  struct path *path, char *errbuff,
+                                  size_t buffsize);
+static void set_pcc_address(struct pcc_state *pcc_state,
+                           struct lsp_nb_key *nbkey, struct ipaddr *addr);
+static int compare_pcc_opts(struct pcc_opts *lhs, struct pcc_opts *rhs);
+static int compare_pce_opts(struct pce_opts *lhs, struct pce_opts *rhs);
+static int get_previous_best_pce(struct pcc_state **pcc);
+static int get_best_pce(struct pcc_state **pcc);
+static int get_pce_count_connected(struct pcc_state **pcc);
+static bool update_best_pce(struct pcc_state **pcc, int best);
+
+/* Data Structure Helper Functions */
+static void lookup_plspid(struct pcc_state *pcc_state, struct path *path);
+static void lookup_nbkey(struct pcc_state *pcc_state, struct path *path);
+static void free_req_entry(struct req_entry *req);
+static struct req_entry *push_new_req(struct pcc_state *pcc_state,
+                                     struct path *path);
+static void repush_req(struct pcc_state *pcc_state, struct req_entry *req);
+static struct req_entry *pop_req(struct pcc_state *pcc_state, uint32_t reqid);
+static bool add_reqid_mapping(struct pcc_state *pcc_state, struct path *path);
+static void remove_reqid_mapping(struct pcc_state *pcc_state,
+                                struct path *path);
+static uint32_t lookup_reqid(struct pcc_state *pcc_state, struct path *path);
+static bool has_pending_req_for(struct pcc_state *pcc_state, struct path *path);
+
+/* Data Structure Callbacks */
+static int plspid_map_cmp(const struct plspid_map_data *a,
+                         const struct plspid_map_data *b);
+static uint32_t plspid_map_hash(const struct plspid_map_data *e);
+static int nbkey_map_cmp(const struct nbkey_map_data *a,
+                        const struct nbkey_map_data *b);
+static uint32_t nbkey_map_hash(const struct nbkey_map_data *e);
+static int req_map_cmp(const struct req_map_data *a,
+                      const struct req_map_data *b);
+static uint32_t req_map_hash(const struct req_map_data *e);
+
+/* Data Structure Declarations */
+DECLARE_HASH(plspid_map, struct plspid_map_data, mi, plspid_map_cmp,
+            plspid_map_hash)
+DECLARE_HASH(nbkey_map, struct nbkey_map_data, mi, nbkey_map_cmp,
+            nbkey_map_hash)
+DECLARE_HASH(req_map, struct req_map_data, mi, req_map_cmp, req_map_hash)
+
+static inline int req_entry_compare(const struct req_entry *a,
+                                   const struct req_entry *b)
+{
+       return a->path->req_id - b->path->req_id;
+}
+RB_GENERATE(req_entry_head, req_entry, entry, req_entry_compare)
+
+
+/* ------------ API Functions ------------ */
+
+struct pcc_state *pcep_pcc_initialize(struct ctrl_state *ctrl_state, int index)
+{
+       struct pcc_state *pcc_state = XCALLOC(MTYPE_PCEP, sizeof(*pcc_state));
+
+       pcc_state->id = index;
+       pcc_state->status = PCEP_PCC_DISCONNECTED;
+       pcc_state->next_reqid = 1;
+       pcc_state->next_plspid = 1;
+
+       RB_INIT(req_entry_head, &pcc_state->requests);
+
+       update_tag(pcc_state);
+       update_originator(pcc_state);
+
+       PCEP_DEBUG("%s PCC initialized", pcc_state->tag);
+
+       return pcc_state;
+}
+
+void pcep_pcc_finalize(struct ctrl_state *ctrl_state,
+                      struct pcc_state *pcc_state)
+{
+       PCEP_DEBUG("%s PCC finalizing...", pcc_state->tag);
+
+       pcep_pcc_disable(ctrl_state, pcc_state);
+
+       if (pcc_state->pcc_opts != NULL) {
+               XFREE(MTYPE_PCEP, pcc_state->pcc_opts);
+               pcc_state->pcc_opts = NULL;
+       }
+       if (pcc_state->pce_opts != NULL) {
+               XFREE(MTYPE_PCEP, pcc_state->pce_opts);
+               pcc_state->pce_opts = NULL;
+       }
+       if (pcc_state->originator != NULL) {
+               XFREE(MTYPE_PCEP, pcc_state->originator);
+               pcc_state->originator = NULL;
+       }
+
+       if (pcc_state->t_reconnect != NULL) {
+               thread_cancel(&pcc_state->t_reconnect);
+               pcc_state->t_reconnect = NULL;
+       }
+
+       if (pcc_state->t_update_best != NULL) {
+               thread_cancel(&pcc_state->t_update_best);
+               pcc_state->t_update_best = NULL;
+       }
+
+       if (pcc_state->t_session_timeout != NULL) {
+               thread_cancel(&pcc_state->t_session_timeout);
+               pcc_state->t_session_timeout = NULL;
+       }
+
+       XFREE(MTYPE_PCEP, pcc_state);
+}
+
+int compare_pcc_opts(struct pcc_opts *lhs, struct pcc_opts *rhs)
+{
+       int retval;
+
+       if (lhs == NULL) {
+               return 1;
+       }
+
+       if (rhs == NULL) {
+               return -1;
+       }
+
+       retval = lhs->port - rhs->port;
+       if (retval != 0) {
+               return retval;
+       }
+
+       retval = lhs->msd - rhs->msd;
+       if (retval != 0) {
+               return retval;
+       }
+
+       if (IS_IPADDR_V4(&lhs->addr)) {
+               retval = memcmp(&lhs->addr.ipaddr_v4, &rhs->addr.ipaddr_v4,
+                               sizeof(lhs->addr.ipaddr_v4));
+               if (retval != 0) {
+                       return retval;
+               }
+       } else if (IS_IPADDR_V6(&lhs->addr)) {
+               retval = memcmp(&lhs->addr.ipaddr_v6, &rhs->addr.ipaddr_v6,
+                               sizeof(lhs->addr.ipaddr_v6));
+               if (retval != 0) {
+                       return retval;
+               }
+       }
+
+       return 0;
+}
+
+int compare_pce_opts(struct pce_opts *lhs, struct pce_opts *rhs)
+{
+       if (lhs == NULL) {
+               return 1;
+       }
+
+       if (rhs == NULL) {
+               return -1;
+       }
+
+       int retval = lhs->port - rhs->port;
+       if (retval != 0) {
+               return retval;
+       }
+
+       retval = strcmp(lhs->pce_name, rhs->pce_name);
+       if (retval != 0) {
+               return retval;
+       }
+
+       retval = lhs->precedence - rhs->precedence;
+       if (retval != 0) {
+               return retval;
+       }
+
+       retval = memcmp(&lhs->addr, &rhs->addr, sizeof(lhs->addr));
+       if (retval != 0) {
+               return retval;
+       }
+
+       return 0;
+}
+
+int pcep_pcc_update(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state,
+                   struct pcc_opts *pcc_opts, struct pce_opts *pce_opts)
+{
+       int ret = 0;
+
+       // If the options did not change, then there is nothing to do
+       if ((compare_pce_opts(pce_opts, pcc_state->pce_opts) == 0)
+           && (compare_pcc_opts(pcc_opts, pcc_state->pcc_opts) == 0)) {
+               return ret;
+       }
+
+       if ((ret = pcep_pcc_disable(ctrl_state, pcc_state))) {
+               XFREE(MTYPE_PCEP, pcc_opts);
+               XFREE(MTYPE_PCEP, pce_opts);
+               return ret;
+       }
+
+       if (pcc_state->pcc_opts != NULL) {
+               XFREE(MTYPE_PCEP, pcc_state->pcc_opts);
+       }
+       if (pcc_state->pce_opts != NULL) {
+               XFREE(MTYPE_PCEP, pcc_state->pce_opts);
+       }
+
+       pcc_state->pcc_opts = pcc_opts;
+       pcc_state->pce_opts = pce_opts;
+
+       if (IS_IPADDR_V4(&pcc_opts->addr)) {
+               pcc_state->pcc_addr_v4 = pcc_opts->addr.ipaddr_v4;
+               SET_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV4);
+       } else {
+               UNSET_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV4);
+       }
+
+       if (IS_IPADDR_V6(&pcc_opts->addr)) {
+               memcpy(&pcc_state->pcc_addr_v6, &pcc_opts->addr.ipaddr_v6,
+                      sizeof(struct in6_addr));
+               SET_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV6);
+       } else {
+               UNSET_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV6);
+       }
+
+       update_tag(pcc_state);
+       update_originator(pcc_state);
+
+       return pcep_pcc_enable(ctrl_state, pcc_state);
+}
+
+void pcep_pcc_reconnect(struct ctrl_state *ctrl_state,
+                       struct pcc_state *pcc_state)
+{
+       if (pcc_state->status == PCEP_PCC_DISCONNECTED)
+               pcep_pcc_enable(ctrl_state, pcc_state);
+}
+
+int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state)
+{
+       char pcc_buff[40];
+       char pce_buff[40];
+
+       assert(pcc_state->status == PCEP_PCC_DISCONNECTED);
+       assert(pcc_state->sess == NULL);
+
+       if (pcc_state->t_reconnect != NULL) {
+               thread_cancel(&pcc_state->t_reconnect);
+               pcc_state->t_reconnect = NULL;
+       }
+
+       select_transport_address(pcc_state);
+
+       /* Even though we are connecting using IPv6. we want to have an IPv4
+        * address so we can handle candidate path with IPv4 endpoints */
+       if (!CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV4)) {
+               if (pcc_state->retry_count < OTHER_FAMILY_MAX_RETRIES) {
+                       flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
+                                 "skipping connection to PCE %s:%d due to "
+                                 "missing PCC IPv4 address",
+                                 ipaddr2str(&pcc_state->pce_opts->addr,
+                                            pce_buff, sizeof(pce_buff)),
+                                 pcc_state->pce_opts->port);
+                       schedule_reconnect(ctrl_state, pcc_state);
+                       return 0;
+               } else {
+                       flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
+                                 "missing IPv4 PCC address, IPv4 candidate "
+                                 "paths will be ignored");
+               }
+       }
+
+       /* Even though we are connecting using IPv4. we want to have an IPv6
+        * address so we can handle candidate path with IPv6 endpoints */
+       if (!CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV6)) {
+               if (pcc_state->retry_count < OTHER_FAMILY_MAX_RETRIES) {
+                       flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
+                                 "skipping connection to PCE %s:%d due to "
+                                 "missing PCC IPv6 address",
+                                 ipaddr2str(&pcc_state->pce_opts->addr,
+                                            pce_buff, sizeof(pce_buff)),
+                                 pcc_state->pce_opts->port);
+                       schedule_reconnect(ctrl_state, pcc_state);
+                       return 0;
+               } else {
+                       flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
+                                 "missing IPv6 PCC address, IPv6 candidate "
+                                 "paths will be ignored");
+               }
+       }
+
+       /* Even if the maximum retries to try to have all the familly addresses
+        * have been spent, we still need the one for the transport familly */
+       if (pcc_state->pcc_addr_tr.ipa_type == IPADDR_NONE) {
+               flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
+                         "skipping connection to PCE %s:%d due to missing "
+                         "PCC address",
+                         ipaddr2str(&pcc_state->pce_opts->addr, pce_buff,
+                                    sizeof(pce_buff)),
+                         pcc_state->pce_opts->port);
+               schedule_reconnect(ctrl_state, pcc_state);
+               return 0;
+       }
+
+       PCEP_DEBUG("%s PCC connecting", pcc_state->tag);
+       pcc_state->sess = pcep_lib_connect(
+               &pcc_state->pcc_addr_tr, pcc_state->pcc_opts->port,
+               &pcc_state->pce_opts->addr, pcc_state->pce_opts->port,
+               pcc_state->pcc_opts->msd, &pcc_state->pce_opts->config_opts);
+
+       if (pcc_state->sess == NULL) {
+               flog_warn(EC_PATH_PCEP_LIB_CONNECT,
+                         "failed to connect to PCE %s:%d from %s:%d",
+                         ipaddr2str(&pcc_state->pce_opts->addr, pce_buff,
+                                    sizeof(pce_buff)),
+                         pcc_state->pce_opts->port,
+                         ipaddr2str(&pcc_state->pcc_addr_tr, pcc_buff,
+                                    sizeof(pcc_buff)),
+                         pcc_state->pcc_opts->port);
+               schedule_reconnect(ctrl_state, pcc_state);
+               return 0;
+       }
+
+       // In case some best pce alternative were waiting to activate
+       if (pcc_state->t_update_best != NULL) {
+               thread_cancel(&pcc_state->t_update_best);
+               pcc_state->t_update_best = NULL;
+       }
+
+       pcc_state->status = PCEP_PCC_CONNECTING;
+
+       return 0;
+}
+
+int pcep_pcc_disable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state)
+{
+       switch (pcc_state->status) {
+       case PCEP_PCC_DISCONNECTED:
+               return 0;
+       case PCEP_PCC_CONNECTING:
+       case PCEP_PCC_SYNCHRONIZING:
+       case PCEP_PCC_OPERATING:
+               PCEP_DEBUG("%s Disconnecting PCC...", pcc_state->tag);
+               cancel_comp_requests(ctrl_state, pcc_state);
+               pcep_lib_disconnect(pcc_state->sess);
+               /* No need to remove if any PCEs is connected */
+               if (get_pce_count_connected(ctrl_state->pcc) == 0) {
+                       pcep_thread_remove_candidate_path_segments(ctrl_state,
+                                                                  pcc_state);
+               }
+               pcc_state->sess = NULL;
+               pcc_state->status = PCEP_PCC_DISCONNECTED;
+               return 0;
+       default:
+               return 1;
+       }
+}
+
+void pcep_pcc_sync_path(struct ctrl_state *ctrl_state,
+                       struct pcc_state *pcc_state, struct path *path)
+{
+       if (pcc_state->status == PCEP_PCC_SYNCHRONIZING) {
+               path->is_synching = true;
+       } else if (pcc_state->status == PCEP_PCC_OPERATING)
+               path->is_synching = false;
+       else
+               return;
+
+       path->go_active = true;
+
+       /* Accumulate the dynamic paths without any LSP so computation
+        * requests can be performed after synchronization */
+       if ((path->type == SRTE_CANDIDATE_TYPE_DYNAMIC)
+           && (path->first_hop == NULL)
+           && !has_pending_req_for(pcc_state, path)) {
+               PCEP_DEBUG("%s Scheduling computation request for path %s",
+                          pcc_state->tag, path->name);
+               push_new_req(pcc_state, path);
+               return;
+       }
+
+       /* Synchronize the path if the PCE supports LSP updates and the
+        * endpoint address familly is supported */
+       if (pcc_state->caps.is_stateful) {
+               if (filter_path(pcc_state, path)) {
+                       PCEP_DEBUG("%s Synchronizing path %s", pcc_state->tag,
+                                  path->name);
+                       send_report(pcc_state, path);
+               } else {
+                       PCEP_DEBUG(
+                               "%s Skipping %s candidate path %s "
+                               "synchronization",
+                               pcc_state->tag,
+                               ipaddr_type_name(&path->nbkey.endpoint),
+                               path->name);
+               }
+       }
+}
+
+void pcep_pcc_sync_done(struct ctrl_state *ctrl_state,
+                       struct pcc_state *pcc_state)
+{
+       struct req_entry *req;
+
+       if (pcc_state->status != PCEP_PCC_SYNCHRONIZING
+           && pcc_state->status != PCEP_PCC_OPERATING)
+               return;
+
+       if (pcc_state->caps.is_stateful
+           && pcc_state->status == PCEP_PCC_SYNCHRONIZING) {
+               struct path *path = pcep_new_path();
+               *path = (struct path){.name = NULL,
+                                     .srp_id = 0,
+                                     .plsp_id = 0,
+                                     .status = PCEP_LSP_OPERATIONAL_DOWN,
+                                     .do_remove = false,
+                                     .go_active = false,
+                                     .was_created = false,
+                                     .was_removed = false,
+                                     .is_synching = false,
+                                     .is_delegated = false,
+                                     .first_hop = NULL,
+                                     .first_metric = NULL};
+               send_report(pcc_state, path);
+               pcep_free_path(path);
+       }
+
+       pcc_state->synchronized = true;
+       pcc_state->status = PCEP_PCC_OPERATING;
+
+       PCEP_DEBUG("%s Synchronization done", pcc_state->tag);
+
+       /* Start the computation request accumulated during synchronization */
+       RB_FOREACH (req, req_entry_head, &pcc_state->requests) {
+               send_comp_request(ctrl_state, pcc_state, req);
+       }
+}
+
+void pcep_pcc_send_report(struct ctrl_state *ctrl_state,
+                         struct pcc_state *pcc_state, struct path *path)
+{
+       if (pcc_state->status != PCEP_PCC_OPERATING)
+               return;
+
+       if (pcc_state->caps.is_stateful) {
+               PCEP_DEBUG("%s Send report for candidate path %s",
+                          pcc_state->tag, path->name);
+               send_report(pcc_state, path);
+       }
+}
+
+/* ------------ Timeout handler ------------ */
+
+void pcep_pcc_timeout_handler(struct ctrl_state *ctrl_state,
+                             struct pcc_state *pcc_state,
+                             enum pcep_ctrl_timer_type type, void *param)
+{
+       struct req_entry *req;
+
+       switch (type) {
+       case TO_COMPUTATION_REQUEST:
+               assert(param != NULL);
+               req = (struct req_entry *)param;
+               pop_req(pcc_state, req->path->req_id);
+               flog_warn(EC_PATH_PCEP_COMPUTATION_REQUEST_TIMEOUT,
+                         "Computation request %d timeout", req->path->req_id);
+               cancel_comp_request(ctrl_state, pcc_state, req);
+               if (req->retry_count++ < MAX_COMPREQ_TRIES) {
+                       repush_req(pcc_state, req);
+                       send_comp_request(ctrl_state, pcc_state, req);
+                       return;
+               }
+               if (pcc_state->caps.is_stateful) {
+                       struct path *path;
+                       PCEP_DEBUG(
+                               "%s Delegating undefined dynamic path %s to PCE %s",
+                               pcc_state->tag, req->path->name,
+                               pcc_state->originator);
+                       path = pcep_copy_path(req->path);
+                       path->is_delegated = true;
+                       send_report(pcc_state, path);
+                       free_req_entry(req);
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+
+/* ------------ Pathd event handler ------------ */
+
+void pcep_pcc_pathd_event_handler(struct ctrl_state *ctrl_state,
+                                 struct pcc_state *pcc_state,
+                                 enum pcep_pathd_event_type type,
+                                 struct path *path)
+{
+       struct req_entry *req;
+
+       if (pcc_state->status != PCEP_PCC_OPERATING)
+               return;
+
+       /* Skipping candidate path with endpoint that do not match the
+        * configured or deduced PCC IP version */
+       if (!filter_path(pcc_state, path)) {
+               PCEP_DEBUG("%s Skipping %s candidate path %s event",
+                          pcc_state->tag,
+                          ipaddr_type_name(&path->nbkey.endpoint), path->name);
+               return;
+       }
+
+       switch (type) {
+       case PCEP_PATH_CREATED:
+               if (has_pending_req_for(pcc_state, path)) {
+                       PCEP_DEBUG(
+                               "%s Candidate path %s created, computation request already sent",
+                               pcc_state->tag, path->name);
+                       return;
+               }
+               PCEP_DEBUG("%s Candidate path %s created", pcc_state->tag,
+                          path->name);
+               if ((path->first_hop == NULL)
+                   && (path->type == SRTE_CANDIDATE_TYPE_DYNAMIC)) {
+                       req = push_new_req(pcc_state, path);
+                       send_comp_request(ctrl_state, pcc_state, req);
+               } else if (pcc_state->caps.is_stateful)
+                       send_report(pcc_state, path);
+               return;
+       case PCEP_PATH_UPDATED:
+               PCEP_DEBUG("%s Candidate path %s updated", pcc_state->tag,
+                          path->name);
+               if (pcc_state->caps.is_stateful)
+                       send_report(pcc_state, path);
+               return;
+       case PCEP_PATH_REMOVED:
+               PCEP_DEBUG("%s Candidate path %s removed", pcc_state->tag,
+                          path->name);
+               path->was_removed = true;
+               if (pcc_state->caps.is_stateful)
+                       send_report(pcc_state, path);
+               return;
+       default:
+               flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
+                         "Unexpected pathd event received by pcc %s: %u",
+                         pcc_state->tag, type);
+               return;
+       }
+}
+
+
+/* ------------ PCEP event handler ------------ */
+
+void pcep_pcc_pcep_event_handler(struct ctrl_state *ctrl_state,
+                                struct pcc_state *pcc_state, pcep_event *event)
+{
+       PCEP_DEBUG("%s Received PCEP event: %s", pcc_state->tag,
+                  pcep_event_type_name(event->event_type));
+       switch (event->event_type) {
+       case PCC_CONNECTED_TO_PCE:
+               assert(PCEP_PCC_CONNECTING == pcc_state->status);
+               PCEP_DEBUG("%s Connection established", pcc_state->tag);
+               pcc_state->status = PCEP_PCC_SYNCHRONIZING;
+               pcc_state->retry_count = 0;
+               pcc_state->synchronized = false;
+               PCEP_DEBUG("%s Starting PCE synchronization", pcc_state->tag);
+               cancel_session_timeout(ctrl_state, pcc_state);
+               pcep_pcc_calculate_best_pce(ctrl_state->pcc);
+               pcep_thread_start_sync(ctrl_state, pcc_state->id);
+               break;
+       case PCC_SENT_INVALID_OPEN:
+               PCEP_DEBUG("%s Sent invalid OPEN message", pcc_state->tag);
+               PCEP_DEBUG(
+                       "%s Reconciling values: keep alive (%d) dead timer (%d) seconds ",
+                       pcc_state->tag,
+                       pcc_state->sess->pcc_config
+                               .keep_alive_pce_negotiated_timer_seconds,
+                       pcc_state->sess->pcc_config
+                               .dead_timer_pce_negotiated_seconds);
+               pcc_state->pce_opts->config_opts.keep_alive_seconds =
+                       pcc_state->sess->pcc_config
+                               .keep_alive_pce_negotiated_timer_seconds;
+               pcc_state->pce_opts->config_opts.dead_timer_seconds =
+                       pcc_state->sess->pcc_config
+                               .dead_timer_pce_negotiated_seconds;
+               break;
+
+       case PCC_RCVD_INVALID_OPEN:
+               PCEP_DEBUG("%s Received invalid OPEN message", pcc_state->tag);
+               PCEP_DEBUG_PCEP("%s PCEP message: %s", pcc_state->tag,
+                               format_pcep_message(event->message));
+               break;
+       case PCE_DEAD_TIMER_EXPIRED:
+       case PCE_CLOSED_SOCKET:
+       case PCE_SENT_PCEP_CLOSE:
+       case PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED:
+       case PCC_PCEP_SESSION_CLOSED:
+       case PCC_RCVD_MAX_INVALID_MSGS:
+       case PCC_RCVD_MAX_UNKOWN_MSGS:
+               pcep_pcc_disable(ctrl_state, pcc_state);
+               schedule_reconnect(ctrl_state, pcc_state);
+               schedule_session_timeout(ctrl_state, pcc_state);
+               break;
+       case MESSAGE_RECEIVED:
+               PCEP_DEBUG_PCEP("%s Received PCEP message: %s", pcc_state->tag,
+                               format_pcep_message(event->message));
+               if (pcc_state->status == PCEP_PCC_CONNECTING) {
+                       if (event->message->msg_header->type == PCEP_TYPE_OPEN)
+                               handle_pcep_open(ctrl_state, pcc_state,
+                                                event->message);
+                       break;
+               }
+               assert(pcc_state->status == PCEP_PCC_SYNCHRONIZING
+                      || pcc_state->status == PCEP_PCC_OPERATING);
+               handle_pcep_message(ctrl_state, pcc_state, event->message);
+               break;
+       default:
+               flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEPLIB_EVENT,
+                         "Unexpected event from pceplib: %s",
+                         format_pcep_event(event));
+               break;
+       }
+}
+
+
+/*------------------ Multi-PCE --------------------- */
+
+/* Internal util function, returns true if sync is necessary, false otherwise */
+bool update_best_pce(struct pcc_state **pcc, int best)
+{
+       PCEP_DEBUG(" recalculating pce precedence ");
+       if (best) {
+               struct pcc_state *best_pcc_state =
+                       pcep_pcc_get_pcc_by_id(pcc, best);
+               if (best_pcc_state->previous_best != best_pcc_state->is_best) {
+                       PCEP_DEBUG(" %s Resynch best (%i) previous best (%i)",
+                                  best_pcc_state->tag, best_pcc_state->id,
+                                  best_pcc_state->previous_best);
+                       return true;
+               } else {
+                       PCEP_DEBUG(
+                               " %s No Resynch best (%i) previous best (%i)",
+                               best_pcc_state->tag, best_pcc_state->id,
+                               best_pcc_state->previous_best);
+               }
+       } else {
+               PCEP_DEBUG(" No best pce available, all pce seem disconnected");
+       }
+
+       return false;
+}
+
+int get_best_pce(struct pcc_state **pcc)
+{
+       for (int i = 0; i < MAX_PCC; i++) {
+               if (pcc[i] && pcc[i]->pce_opts) {
+                       if (pcc[i]->is_best == true) {
+                               return pcc[i]->id;
+                       }
+               }
+       }
+       return 0;
+}
+
+int get_pce_count_connected(struct pcc_state **pcc)
+{
+       int count = 0;
+       for (int i = 0; i < MAX_PCC; i++) {
+               if (pcc[i] && pcc[i]->pce_opts
+                   && pcc[i]->status != PCEP_PCC_DISCONNECTED) {
+                       count++;
+               }
+       }
+       return count;
+}
+
+int get_previous_best_pce(struct pcc_state **pcc)
+{
+       int previous_best_pce = -1;
+
+       for (int i = 0; i < MAX_PCC; i++) {
+               if (pcc[i] && pcc[i]->pce_opts && pcc[i]->previous_best == true
+                   && pcc[i]->status != PCEP_PCC_DISCONNECTED) {
+                       previous_best_pce = i;
+                       break;
+               }
+       }
+       return previous_best_pce != -1 ? pcc[previous_best_pce]->id : 0;
+}
+
+/* Called by path_pcep_controller EV_REMOVE_PCC
+ * Event handler when a PCC is removed. */
+int pcep_pcc_multi_pce_remove_pcc(struct ctrl_state *ctrl_state,
+                                 struct pcc_state **pcc)
+{
+       int new_best_pcc_id = -1;
+       new_best_pcc_id = pcep_pcc_calculate_best_pce(pcc);
+       if (new_best_pcc_id) {
+               if (update_best_pce(ctrl_state->pcc, new_best_pcc_id) == true) {
+                       pcep_thread_start_sync(ctrl_state, new_best_pcc_id);
+               }
+       }
+
+       return 0;
+}
+
+/* Called by path_pcep_controller EV_SYNC_PATH
+ * Event handler when a path is sync'd. */
+int pcep_pcc_multi_pce_sync_path(struct ctrl_state *ctrl_state, int pcc_id,
+                                struct pcc_state **pcc)
+{
+       int previous_best_pcc_id = -1;
+
+       if (pcc_id == get_best_pce(pcc)) {
+               previous_best_pcc_id = get_previous_best_pce(pcc);
+               if (previous_best_pcc_id != 0) {
+                       /* while adding new pce, path has to resync to the
+                        * previous best. pcep_thread_start_sync() will be
+                        * called by the calling function */
+                       if (update_best_pce(ctrl_state->pcc,
+                                           previous_best_pcc_id)
+                           == true) {
+                               cancel_comp_requests(
+                                       ctrl_state,
+                                       pcep_pcc_get_pcc_by_id(
+                                               pcc, previous_best_pcc_id));
+                               pcep_thread_start_sync(ctrl_state,
+                                                      previous_best_pcc_id);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/* Called by path_pcep_controller when the TM_CALCULATE_BEST_PCE
+ * timer expires */
+int pcep_pcc_timer_update_best_pce(struct ctrl_state *ctrl_state, int pcc_id)
+{
+       int ret = 0;
+       /* resync whatever was the new best */
+       int prev_best = get_best_pce(ctrl_state->pcc);
+       int best_id = pcep_pcc_calculate_best_pce(ctrl_state->pcc);
+       if (best_id && prev_best != best_id) { // Avoid Multiple call
+               struct pcc_state *pcc_state =
+                       pcep_pcc_get_pcc_by_id(ctrl_state->pcc, best_id);
+               if (update_best_pce(ctrl_state->pcc, pcc_state->id) == true) {
+                       pcep_thread_start_sync(ctrl_state, pcc_state->id);
+               }
+       }
+
+       return ret;
+}
+
+/* Called by path_pcep_controller::pcep_thread_event_update_pce_options()
+ * Returns the best PCE id */
+int pcep_pcc_calculate_best_pce(struct pcc_state **pcc)
+{
+       int best_precedence = 255; // DEFAULT_PCE_PRECEDENCE;
+       int best_pce = -1;
+       int one_connected_pce = -1;
+       int previous_best_pce = -1;
+       int step_0_best = -1;
+       int step_0_previous = -1;
+       int pcc_count = 0;
+
+       // Get state
+       for (int i = 0; i < MAX_PCC; i++) {
+               if (pcc[i] && pcc[i]->pce_opts) {
+                       zlog_debug(
+                               "multi-pce: calculate all : i (%i) is_best (%i) previous_best (%i)   ",
+                               i, pcc[i]->is_best, pcc[i]->previous_best);
+                       pcc_count++;
+
+                       if (pcc[i]->is_best == true) {
+                               step_0_best = i;
+                       }
+                       if (pcc[i]->previous_best == true) {
+                               step_0_previous = i;
+                       }
+               }
+       }
+
+       if (!pcc_count) {
+               return 0;
+       }
+
+       // Calculate best
+       for (int i = 0; i < MAX_PCC; i++) {
+               if (pcc[i] && pcc[i]->pce_opts
+                   && pcc[i]->status != PCEP_PCC_DISCONNECTED) {
+                       one_connected_pce = i; // In case none better
+                       if (pcc[i]->pce_opts->precedence <= best_precedence) {
+                               if (best_pce != -1
+                                   && pcc[best_pce]->pce_opts->precedence
+                                              == pcc[i]->pce_opts
+                                                         ->precedence) {
+                                       if (ipaddr_cmp(
+                                                   &pcc[i]->pce_opts->addr,
+                                                   &pcc[best_pce]
+                                                            ->pce_opts->addr)
+                                           > 0)
+                                               // collide of precedences so
+                                               // compare ip
+                                               best_pce = i;
+                               } else {
+                                       if (!pcc[i]->previous_best) {
+                                               best_precedence =
+                                                       pcc[i]->pce_opts
+                                                               ->precedence;
+                                               best_pce = i;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       zlog_debug(
+               "multi-pce: calculate data : sb (%i) sp (%i) oc (%i) b (%i)  ",
+               step_0_best, step_0_previous, one_connected_pce, best_pce);
+
+       // Changed of state so ...
+       if (step_0_best != best_pce) {
+               // Calculate previous
+               previous_best_pce = step_0_best;
+               // Clean state
+               if (step_0_best != -1) {
+                       pcc[step_0_best]->is_best = false;
+               }
+               if (step_0_previous != -1) {
+                       pcc[step_0_previous]->previous_best = false;
+               }
+
+               // Set previous
+               if (previous_best_pce != -1
+                   && pcc[previous_best_pce]->status
+                              == PCEP_PCC_DISCONNECTED) {
+                       pcc[previous_best_pce]->previous_best = true;
+                       zlog_debug("multi-pce: previous best pce (%i) ",
+                                  previous_best_pce + 1);
+               }
+
+
+               // Set best
+               if (best_pce != -1) {
+                       pcc[best_pce]->is_best = true;
+                       zlog_debug("multi-pce: best pce (%i) ", best_pce + 1);
+               } else {
+                       if (one_connected_pce != -1) {
+                               best_pce = one_connected_pce;
+                               pcc[one_connected_pce]->is_best = true;
+                               zlog_debug(
+                                       "multi-pce: one connected best pce (default) (%i) ",
+                                       one_connected_pce + 1);
+                       } else {
+                               for (int i = 0; i < MAX_PCC; i++) {
+                                       if (pcc[i] && pcc[i]->pce_opts) {
+                                               best_pce = i;
+                                               pcc[i]->is_best = true;
+                                               zlog_debug(
+                                                       "(disconnected) best pce (default) (%i) ",
+                                                       i + 1);
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return ((best_pce == -1) ? 0 : pcc[best_pce]->id);
+}
+
+int pcep_pcc_get_pcc_id_by_ip_port(struct pcc_state **pcc,
+                                  struct pce_opts *pce_opts)
+{
+       if (pcc == NULL) {
+               return 0;
+       }
+
+       for (int idx = 0; idx < MAX_PCC; idx++) {
+               if (pcc[idx]) {
+                       if ((ipaddr_cmp((const struct ipaddr *)&pcc[idx]
+                                               ->pce_opts->addr,
+                                       (const struct ipaddr *)&pce_opts->addr)
+                            == 0)
+                           && pcc[idx]->pce_opts->port == pce_opts->port) {
+                               zlog_debug("found pcc_id (%d) idx (%d)",
+                                          pcc[idx]->id, idx);
+                               return pcc[idx]->id;
+                       }
+               }
+       }
+       return 0;
+}
+
+int pcep_pcc_get_pcc_id_by_idx(struct pcc_state **pcc, int idx)
+{
+       if (pcc == NULL || idx < 0) {
+               return 0;
+       }
+
+       return pcc[idx] ? pcc[idx]->id : 0;
+}
+
+struct pcc_state *pcep_pcc_get_pcc_by_id(struct pcc_state **pcc, int id)
+{
+       if (pcc == NULL || id < 0) {
+               return NULL;
+       }
+
+       for (int i = 0; i < MAX_PCC; i++) {
+               if (pcc[i]) {
+                       if (pcc[i]->id == id) {
+                               zlog_debug("found id (%d) pcc_idx (%d)",
+                                          pcc[i]->id, i);
+                               return pcc[i];
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+struct pcc_state *pcep_pcc_get_pcc_by_name(struct pcc_state **pcc,
+                                          const char *pce_name)
+{
+       if (pcc == NULL || pce_name == NULL) {
+               return NULL;
+       }
+
+       for (int i = 0; i < MAX_PCC; i++) {
+               if (pcc[i] == NULL) {
+                       continue;
+               }
+
+               if (strcmp(pcc[i]->pce_opts->pce_name, pce_name) == 0) {
+                       return pcc[i];
+               }
+       }
+
+       return NULL;
+}
+
+int pcep_pcc_get_pcc_idx_by_id(struct pcc_state **pcc, int id)
+{
+       if (pcc == NULL) {
+               return -1;
+       }
+
+       for (int idx = 0; idx < MAX_PCC; idx++) {
+               if (pcc[idx]) {
+                       if (pcc[idx]->id == id) {
+                               zlog_debug("found pcc_id (%d) array_idx (%d)",
+                                          pcc[idx]->id, idx);
+                               return idx;
+                       }
+               }
+       }
+
+       return -1;
+}
+
+int pcep_pcc_get_free_pcc_idx(struct pcc_state **pcc)
+{
+       assert(pcc != NULL);
+
+       for (int idx = 0; idx < MAX_PCC; idx++) {
+               if (pcc[idx] == NULL) {
+                       zlog_debug("new pcc_idx (%d)", idx);
+                       return idx;
+               }
+       }
+
+       return -1;
+}
+
+int pcep_pcc_get_pcc_id(struct pcc_state *pcc)
+{
+       return ((pcc == NULL) ? 0 : pcc->id);
+}
+
+void pcep_pcc_copy_pcc_info(struct pcc_state **pcc,
+                           struct pcep_pcc_info *pcc_info)
+{
+       struct pcc_state *pcc_state =
+               pcep_pcc_get_pcc_by_name(pcc, pcc_info->pce_name);
+       if (!pcc_state) {
+               return;
+       }
+
+       pcc_info->ctrl_state = NULL;
+       pcc_info->msd = pcc_state->pcc_opts->msd;
+       pcc_info->pcc_port = pcc_state->pcc_opts->port;
+       pcc_info->next_plspid = pcc_state->next_plspid;
+       pcc_info->next_reqid = pcc_state->next_reqid;
+       pcc_info->status = pcc_state->status;
+       pcc_info->pcc_id = pcc_state->id;
+       pcc_info->is_best_multi_pce = pcc_state->is_best;
+       pcc_info->previous_best = pcc_state->previous_best;
+       pcc_info->precedence =
+               pcc_state->pce_opts ? pcc_state->pce_opts->precedence : 0;
+       memcpy(&pcc_info->pcc_addr, &pcc_state->pcc_addr_tr,
+              sizeof(struct ipaddr));
+}
+
+
+/*------------------ PCEP Message handlers --------------------- */
+
+void handle_pcep_open(struct ctrl_state *ctrl_state,
+                     struct pcc_state *pcc_state, struct pcep_message *msg)
+{
+       assert(msg->msg_header->type == PCEP_TYPE_OPEN);
+       pcep_lib_parse_capabilities(msg, &pcc_state->caps);
+       PCEP_DEBUG("PCE capabilities: %s, %s%s",
+                  pcc_state->caps.is_stateful ? "stateful" : "stateless",
+                  pcc_state->caps.supported_ofs_are_known
+                          ? (pcc_state->caps.supported_ofs == 0
+                                     ? "no objective functions supported"
+                                     : "supported objective functions are ")
+                          : "supported objective functions are unknown",
+                  format_objfun_set(pcc_state->caps.supported_ofs));
+}
+
+void handle_pcep_message(struct ctrl_state *ctrl_state,
+                        struct pcc_state *pcc_state, struct pcep_message *msg)
+{
+       if (pcc_state->status != PCEP_PCC_OPERATING)
+               return;
+
+       switch (msg->msg_header->type) {
+       case PCEP_TYPE_INITIATE:
+               handle_pcep_lsp_initiate(ctrl_state, pcc_state, msg);
+               break;
+       case PCEP_TYPE_UPDATE:
+               handle_pcep_lsp_update(ctrl_state, pcc_state, msg);
+               break;
+       case PCEP_TYPE_PCREP:
+               handle_pcep_comp_reply(ctrl_state, pcc_state, msg);
+               break;
+       default:
+               flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_MESSAGE,
+                         "Unexpected pcep message from pceplib: %s",
+                         format_pcep_message(msg));
+               break;
+       }
+}
+
+void handle_pcep_lsp_update(struct ctrl_state *ctrl_state,
+                           struct pcc_state *pcc_state,
+                           struct pcep_message *msg)
+{
+       char err[MAX_ERROR_MSG_SIZE] = "";
+       struct path *path;
+       path = pcep_lib_parse_path(msg);
+       lookup_nbkey(pcc_state, path);
+       /* TODO: Investigate if this is safe to do in the controller thread */
+       path_pcep_config_lookup(path);
+       specialize_incoming_path(pcc_state, path);
+       PCEP_DEBUG("%s Received LSP update", pcc_state->tag);
+       PCEP_DEBUG_PATH("%s", format_path(path));
+
+       if (validate_incoming_path(pcc_state, path, err, sizeof(err)))
+               pcep_thread_update_path(ctrl_state, pcc_state->id, path);
+       else {
+               /* FIXME: Monitor the amount of errors from the PCE and
+                * possibly disconnect and blacklist */
+               flog_warn(EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE,
+                         "Unsupported PCEP protocol feature: %s", err);
+               pcep_free_path(path);
+       }
+}
+
+void handle_pcep_lsp_initiate(struct ctrl_state *ctrl_state,
+                             struct pcc_state *pcc_state,
+                             struct pcep_message *msg)
+{
+       PCEP_DEBUG("%s Received LSP initiate, not supported yet",
+                  pcc_state->tag);
+
+       /* TODO when we support both PCC and PCE initiated sessions,
+        *      we should first check the session type before
+        *      rejecting this message. */
+       send_pcep_error(pcc_state, PCEP_ERRT_INVALID_OPERATION,
+                       PCEP_ERRV_LSP_NOT_PCE_INITIATED);
+}
+
+void handle_pcep_comp_reply(struct ctrl_state *ctrl_state,
+                           struct pcc_state *pcc_state,
+                           struct pcep_message *msg)
+{
+       char err[MAX_ERROR_MSG_SIZE] = "";
+       struct req_entry *req;
+       struct path *path;
+
+       path = pcep_lib_parse_path(msg);
+       req = pop_req(pcc_state, path->req_id);
+       if (req == NULL) {
+               /* TODO: check the rate of bad computation reply and close
+                * the connection if more that a given rate.
+                */
+               PCEP_DEBUG(
+                       "%s Received computation reply for unknown request "
+                       "%d",
+                       pcc_state->tag, path->req_id);
+               PCEP_DEBUG_PATH("%s", format_path(path));
+               send_pcep_error(pcc_state, PCEP_ERRT_UNKNOWN_REQ_REF,
+                               PCEP_ERRV_UNASSIGNED);
+               return;
+       }
+
+       /* Cancel the computation request timeout */
+       pcep_thread_cancel_timer(&req->t_retry);
+
+       /* Transfer relevent metadata from the request to the response */
+       path->nbkey = req->path->nbkey;
+       path->plsp_id = req->path->plsp_id;
+       path->type = req->path->type;
+       path->name = XSTRDUP(MTYPE_PCEP, req->path->name);
+       specialize_incoming_path(pcc_state, path);
+
+       PCEP_DEBUG("%s Received computation reply %d (no-path: %s)",
+                  pcc_state->tag, path->req_id,
+                  path->no_path ? "true" : "false");
+       PCEP_DEBUG_PATH("%s", format_path(path));
+
+       if (path->no_path) {
+               PCEP_DEBUG("%s Computation for path %s did not find any result",
+                          pcc_state->tag, path->name);
+       } else if (validate_incoming_path(pcc_state, path, err, sizeof(err))) {
+               /* Updating a dynamic path will automatically delegate it */
+               pcep_thread_update_path(ctrl_state, pcc_state->id, path);
+               free_req_entry(req);
+               return;
+       } else {
+               /* FIXME: Monitor the amount of errors from the PCE and
+                * possibly disconnect and blacklist */
+               flog_warn(EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE,
+                         "Unsupported PCEP protocol feature: %s", err);
+       }
+
+       pcep_free_path(path);
+
+       /* Delegate the path regardless of the outcome */
+       /* TODO: For now we are using the path from the request, when
+        * pathd API is thread safe, we could get a new path */
+       if (pcc_state->caps.is_stateful) {
+               PCEP_DEBUG("%s Delegating undefined dynamic path %s to PCE %s",
+                          pcc_state->tag, path->name, pcc_state->originator);
+               path = pcep_copy_path(req->path);
+               path->is_delegated = true;
+               send_report(pcc_state, path);
+               pcep_free_path(path);
+       }
+
+       free_req_entry(req);
+}
+
+
+/* ------------ Internal Functions ------------ */
+
+const char *ipaddr_type_name(struct ipaddr *addr)
+{
+       if (IS_IPADDR_V4(addr))
+               return "IPv4";
+       if (IS_IPADDR_V6(addr))
+               return "IPv6";
+       return "undefined";
+}
+
+bool filter_path(struct pcc_state *pcc_state, struct path *path)
+{
+       return (IS_IPADDR_V4(&path->nbkey.endpoint)
+               && CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV4))
+              || (IS_IPADDR_V6(&path->nbkey.endpoint)
+                  && CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV6));
+}
+
+void select_pcc_addresses(struct pcc_state *pcc_state)
+{
+       /* If no IPv4 address was specified, try to get one from zebra */
+       if (!CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV4)) {
+               if (get_ipv4_router_id(&pcc_state->pcc_addr_v4)) {
+                       SET_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV4);
+               }
+       }
+
+       /* If no IPv6 address was specified, try to get one from zebra */
+       if (!CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV6)) {
+               if (get_ipv6_router_id(&pcc_state->pcc_addr_v6)) {
+                       SET_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV6);
+               }
+       }
+}
+
+void select_transport_address(struct pcc_state *pcc_state)
+{
+       struct ipaddr *taddr = &pcc_state->pcc_addr_tr;
+
+       select_pcc_addresses(pcc_state);
+
+       taddr->ipa_type = IPADDR_NONE;
+
+       /* Select a transport source address in function of the configured PCE
+        * address */
+       if (IS_IPADDR_V4(&pcc_state->pce_opts->addr)) {
+               if (CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV4)) {
+                       taddr->ipa_type = IPADDR_V4;
+                       taddr->ipaddr_v4 = pcc_state->pcc_addr_v4;
+               }
+       } else {
+               if (CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV6)) {
+                       taddr->ipa_type = IPADDR_V6;
+                       taddr->ipaddr_v6 = pcc_state->pcc_addr_v6;
+               }
+       }
+}
+
+void update_tag(struct pcc_state *pcc_state)
+{
+       if (pcc_state->pce_opts != NULL) {
+               assert(!IS_IPADDR_NONE(&pcc_state->pce_opts->addr));
+               if (IS_IPADDR_V6(&pcc_state->pce_opts->addr)) {
+                       snprintfrr(pcc_state->tag, sizeof(pcc_state->tag),
+                                  "%pI6:%i (%u)",
+                                  &pcc_state->pce_opts->addr.ipaddr_v6,
+                                  pcc_state->pce_opts->port, pcc_state->id);
+               } else {
+                       snprintfrr(pcc_state->tag, sizeof(pcc_state->tag),
+                                  "%pI4:%i (%u)",
+                                  &pcc_state->pce_opts->addr.ipaddr_v4,
+                                  pcc_state->pce_opts->port, pcc_state->id);
+               }
+       } else {
+               snprintfrr(pcc_state->tag, sizeof(pcc_state->tag), "(%u)",
+                          pcc_state->id);
+       }
+}
+
+void update_originator(struct pcc_state *pcc_state)
+{
+       char *originator;
+       if (pcc_state->originator != NULL) {
+               XFREE(MTYPE_PCEP, pcc_state->originator);
+               pcc_state->originator = NULL;
+       }
+       if (pcc_state->pce_opts == NULL)
+               return;
+       originator = XCALLOC(MTYPE_PCEP, 52);
+       assert(!IS_IPADDR_NONE(&pcc_state->pce_opts->addr));
+       if (IS_IPADDR_V6(&pcc_state->pce_opts->addr)) {
+               snprintfrr(originator, 52, "%pI6:%i",
+                          &pcc_state->pce_opts->addr.ipaddr_v6,
+                          pcc_state->pce_opts->port);
+       } else {
+               snprintfrr(originator, 52, "%pI4:%i",
+                          &pcc_state->pce_opts->addr.ipaddr_v4,
+                          pcc_state->pce_opts->port);
+       }
+       pcc_state->originator = originator;
+}
+
+void schedule_reconnect(struct ctrl_state *ctrl_state,
+                       struct pcc_state *pcc_state)
+{
+       pcc_state->retry_count++;
+       pcep_thread_schedule_reconnect(ctrl_state, pcc_state->id,
+                                      pcc_state->retry_count,
+                                      &pcc_state->t_reconnect);
+       if (pcc_state->retry_count == 1) {
+               pcep_thread_schedule_sync_best_pce(
+                       ctrl_state, pcc_state->id,
+                       pcc_state->pce_opts->config_opts
+                               .delegation_timeout_seconds,
+                       &pcc_state->t_update_best);
+       }
+}
+
+void schedule_session_timeout(struct ctrl_state *ctrl_state,
+                             struct pcc_state *pcc_state)
+{
+       /* No need to schedule timeout if multiple PCEs are connected */
+       if (get_pce_count_connected(ctrl_state->pcc)) {
+               PCEP_DEBUG_PCEP(
+                       "schedule_session_timeout not setting timer for multi-pce mode");
+
+               return;
+       }
+
+       pcep_thread_schedule_session_timeout(
+               ctrl_state, pcep_pcc_get_pcc_id(pcc_state),
+               pcc_state->pce_opts->config_opts
+                       .session_timeout_inteval_seconds,
+               &pcc_state->t_session_timeout);
+}
+
+void cancel_session_timeout(struct ctrl_state *ctrl_state,
+                           struct pcc_state *pcc_state)
+{
+       /* No need to schedule timeout if multiple PCEs are connected */
+       if (pcc_state->t_session_timeout == NULL) {
+               PCEP_DEBUG_PCEP("cancel_session_timeout timer thread NULL");
+               return;
+       }
+
+       PCEP_DEBUG_PCEP("Cancel session_timeout timer");
+       pcep_thread_cancel_timer(&pcc_state->t_session_timeout);
+       pcc_state->t_session_timeout = NULL;
+}
+
+void send_pcep_message(struct pcc_state *pcc_state, struct pcep_message *msg)
+{
+       if (pcc_state->sess != NULL) {
+               PCEP_DEBUG_PCEP("%s Sending PCEP message: %s", pcc_state->tag,
+                               format_pcep_message(msg));
+               send_message(pcc_state->sess, msg, true);
+       }
+}
+
+void send_pcep_error(struct pcc_state *pcc_state,
+                    enum pcep_error_type error_type,
+                    enum pcep_error_value error_value)
+{
+       struct pcep_message *msg;
+       PCEP_DEBUG("%s Sending PCEP error type %s (%d) value %s (%d)",
+                  pcc_state->tag, pcep_error_type_name(error_type), error_type,
+                  pcep_error_value_name(error_type, error_value), error_value);
+       msg = pcep_lib_format_error(error_type, error_value);
+       send_pcep_message(pcc_state, msg);
+}
+
+void send_report(struct pcc_state *pcc_state, struct path *path)
+{
+       struct pcep_message *report;
+
+       path->req_id = 0;
+       specialize_outgoing_path(pcc_state, path);
+       PCEP_DEBUG_PATH("%s Sending path %s: %s", pcc_state->tag, path->name,
+                       format_path(path));
+       report = pcep_lib_format_report(&pcc_state->caps, path);
+       send_pcep_message(pcc_state, report);
+}
+
+/* Updates the path for the PCE, updating the delegation and creation flags */
+void specialize_outgoing_path(struct pcc_state *pcc_state, struct path *path)
+{
+       bool is_delegated = false;
+       bool was_created = false;
+
+       lookup_plspid(pcc_state, path);
+
+       set_pcc_address(pcc_state, &path->nbkey, &path->pcc_addr);
+       path->sender = pcc_state->pcc_addr_tr;
+
+       /* TODO: When the pathd API have a way to mark a path as
+        * delegated, use it instead of considering all dynamic path
+        * delegated. We need to disable the originator check for now,
+        * because path could be delegated without having any originator yet */
+       // if ((path->originator == NULL)
+       //     || (strcmp(path->originator, pcc_state->originator) == 0)) {
+       //      is_delegated = (path->type == SRTE_CANDIDATE_TYPE_DYNAMIC)
+       //                      && (path->first_hop != NULL);
+       //      /* it seems the PCE consider updating an LSP a creation ?!?
+       //      at least Cisco does... */
+       //      was_created = path->update_origin == SRTE_ORIGIN_PCEP;
+       // }
+       is_delegated = (path->type == SRTE_CANDIDATE_TYPE_DYNAMIC);
+       was_created = path->update_origin == SRTE_ORIGIN_PCEP;
+
+       path->pcc_id = pcc_state->id;
+       path->go_active = is_delegated && pcc_state->is_best;
+       path->is_delegated = is_delegated && pcc_state->is_best;
+       path->was_created = was_created;
+}
+
+/* Updates the path for the PCC */
+void specialize_incoming_path(struct pcc_state *pcc_state, struct path *path)
+{
+       set_pcc_address(pcc_state, &path->nbkey, &path->pcc_addr);
+       path->sender = pcc_state->pce_opts->addr;
+       path->pcc_id = pcc_state->id;
+       path->update_origin = SRTE_ORIGIN_PCEP;
+       path->originator = XSTRDUP(MTYPE_PCEP, pcc_state->originator);
+}
+
+/* Ensure the path can be handled by the PCC and if not, sends an error */
+bool validate_incoming_path(struct pcc_state *pcc_state, struct path *path,
+                           char *errbuff, size_t buffsize)
+{
+       struct path_hop *hop;
+       enum pcep_error_type err_type = 0;
+       enum pcep_error_value err_value = PCEP_ERRV_UNASSIGNED;
+
+       for (hop = path->first_hop; hop != NULL; hop = hop->next) {
+               /* Hops without SID are not supported */
+               if (!hop->has_sid) {
+                       snprintfrr(errbuff, buffsize, "SR segment without SID");
+                       err_type = PCEP_ERRT_RECEPTION_OF_INV_OBJECT;
+                       err_value = PCEP_ERRV_DISJOINTED_CONF_TLV_MISSING;
+                       break;
+               }
+               /* Hops with non-MPLS SID are not supported */
+               if (!hop->is_mpls) {
+                       snprintfrr(errbuff, buffsize,
+                                  "SR segment with non-MPLS SID");
+                       err_type = PCEP_ERRT_RECEPTION_OF_INV_OBJECT;
+                       err_value = PCEP_ERRV_UNSUPPORTED_NAI;
+                       break;
+               }
+       }
+
+       if (err_type != 0) {
+               send_pcep_error(pcc_state, err_type, err_value);
+               return false;
+       }
+
+       return true;
+}
+
+void send_comp_request(struct ctrl_state *ctrl_state,
+                      struct pcc_state *pcc_state, struct req_entry *req)
+{
+       assert(req != NULL);
+
+       if (req->t_retry)
+               return;
+
+       assert(req->path != NULL);
+       assert(req->path->req_id > 0);
+       assert(RB_FIND(req_entry_head, &pcc_state->requests, req) == req);
+       assert(lookup_reqid(pcc_state, req->path) == req->path->req_id);
+
+       int timeout;
+       char buff[40];
+       struct pcep_message *msg;
+
+       if (!pcc_state->is_best) {
+               return;
+       }
+       /* TODO: Add a timer to retry the computation request ? */
+
+       specialize_outgoing_path(pcc_state, req->path);
+
+       PCEP_DEBUG(
+               "%s Sending computation request %d for path %s to %s (retry %d)",
+               pcc_state->tag, req->path->req_id, req->path->name,
+               ipaddr2str(&req->path->nbkey.endpoint, buff, sizeof(buff)),
+               req->retry_count);
+       PCEP_DEBUG_PATH("%s Computation request path %s: %s", pcc_state->tag,
+                       req->path->name, format_path(req->path));
+
+       msg = pcep_lib_format_request(&pcc_state->caps, req->path);
+       send_pcep_message(pcc_state, msg);
+       req->was_sent = true;
+
+       /* TODO: Enable this back when the pcep config changes are merged back
+        */
+       // timeout = pcc_state->pce_opts->config_opts.pcep_request_time_seconds;
+       timeout = 30;
+       pcep_thread_schedule_timeout(ctrl_state, pcc_state->id,
+                                    TO_COMPUTATION_REQUEST, timeout,
+                                    (void *)req, &req->t_retry);
+}
+
+void cancel_comp_requests(struct ctrl_state *ctrl_state,
+                         struct pcc_state *pcc_state)
+{
+       struct req_entry *req, *safe_req;
+
+       RB_FOREACH_SAFE (req, req_entry_head, &pcc_state->requests, safe_req) {
+               cancel_comp_request(ctrl_state, pcc_state, req);
+               RB_REMOVE(req_entry_head, &pcc_state->requests, req);
+               remove_reqid_mapping(pcc_state, req->path);
+               free_req_entry(req);
+       }
+}
+
+void cancel_comp_request(struct ctrl_state *ctrl_state,
+                        struct pcc_state *pcc_state, struct req_entry *req)
+{
+       char buff[40];
+       struct pcep_message *msg;
+
+       if (req->was_sent) {
+               /* TODO: Send a computation request cancelation
+                * notification to the PCE */
+               pcep_thread_cancel_timer(&req->t_retry);
+       }
+
+       PCEP_DEBUG(
+               "%s Canceling computation request %d for path %s to %s (retry %d)",
+               pcc_state->tag, req->path->req_id, req->path->name,
+               ipaddr2str(&req->path->nbkey.endpoint, buff, sizeof(buff)),
+               req->retry_count);
+       PCEP_DEBUG_PATH("%s Canceled computation request path %s: %s",
+                       pcc_state->tag, req->path->name,
+                       format_path(req->path));
+
+       msg = pcep_lib_format_request_cancelled(req->path->req_id);
+       send_pcep_message(pcc_state, msg);
+}
+
+void set_pcc_address(struct pcc_state *pcc_state, struct lsp_nb_key *nbkey,
+                    struct ipaddr *addr)
+{
+       select_pcc_addresses(pcc_state);
+       if (IS_IPADDR_V6(&nbkey->endpoint)) {
+               assert(CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV6));
+               addr->ipa_type = IPADDR_V6;
+               addr->ipaddr_v6 = pcc_state->pcc_addr_v6;
+       } else if (IS_IPADDR_V4(&nbkey->endpoint)) {
+               assert(CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV4));
+               addr->ipa_type = IPADDR_V4;
+               addr->ipaddr_v4 = pcc_state->pcc_addr_v4;
+       } else {
+               addr->ipa_type = IPADDR_NONE;
+       }
+}
+
+
+/* ------------ Data Structure Helper Functions ------------ */
+
+void lookup_plspid(struct pcc_state *pcc_state, struct path *path)
+{
+       struct plspid_map_data key, *plspid_mapping;
+       struct nbkey_map_data *nbkey_mapping;
+
+       if (path->nbkey.color != 0) {
+               key.nbkey = path->nbkey;
+               plspid_mapping = plspid_map_find(&pcc_state->plspid_map, &key);
+               if (plspid_mapping == NULL) {
+                       plspid_mapping =
+                               XCALLOC(MTYPE_PCEP, sizeof(*plspid_mapping));
+                       plspid_mapping->nbkey = key.nbkey;
+                       plspid_mapping->plspid = pcc_state->next_plspid;
+                       plspid_map_add(&pcc_state->plspid_map, plspid_mapping);
+                       nbkey_mapping =
+                               XCALLOC(MTYPE_PCEP, sizeof(*nbkey_mapping));
+                       nbkey_mapping->nbkey = key.nbkey;
+                       nbkey_mapping->plspid = pcc_state->next_plspid;
+                       nbkey_map_add(&pcc_state->nbkey_map, nbkey_mapping);
+                       pcc_state->next_plspid++;
+                       // FIXME: Send some error to the PCE isntead of crashing
+                       assert(pcc_state->next_plspid <= 1048576);
+               }
+               path->plsp_id = plspid_mapping->plspid;
+       }
+}
+
+void lookup_nbkey(struct pcc_state *pcc_state, struct path *path)
+{
+       struct nbkey_map_data key, *mapping;
+       // TODO: Should give an error to the PCE instead of crashing
+       assert(path->plsp_id != 0);
+       key.plspid = path->plsp_id;
+       mapping = nbkey_map_find(&pcc_state->nbkey_map, &key);
+       assert(mapping != NULL);
+       path->nbkey = mapping->nbkey;
+}
+
+void free_req_entry(struct req_entry *req)
+{
+       pcep_free_path(req->path);
+       XFREE(MTYPE_PCEP, req);
+}
+
+struct req_entry *push_new_req(struct pcc_state *pcc_state, struct path *path)
+{
+       struct req_entry *req;
+
+       req = XCALLOC(MTYPE_PCEP, sizeof(*req));
+       req->retry_count = 0;
+       req->path = pcep_copy_path(path);
+       repush_req(pcc_state, req);
+
+       return req;
+}
+
+void repush_req(struct pcc_state *pcc_state, struct req_entry *req)
+{
+       uint32_t reqid = pcc_state->next_reqid;
+       void *res;
+
+       req->was_sent = false;
+       req->path->req_id = reqid;
+       res = RB_INSERT(req_entry_head, &pcc_state->requests, req);
+       assert(res == NULL);
+       assert(add_reqid_mapping(pcc_state, req->path) == true);
+
+       pcc_state->next_reqid += 1;
+       /* Wrapping is allowed, but 0 is not a valid id */
+       if (pcc_state->next_reqid == 0)
+               pcc_state->next_reqid = 1;
+}
+
+struct req_entry *pop_req(struct pcc_state *pcc_state, uint32_t reqid)
+{
+       struct path path = {.req_id = reqid};
+       struct req_entry key = {.path = &path};
+       struct req_entry *req;
+
+       req = RB_FIND(req_entry_head, &pcc_state->requests, &key);
+       if (req == NULL)
+               return NULL;
+       RB_REMOVE(req_entry_head, &pcc_state->requests, req);
+       remove_reqid_mapping(pcc_state, req->path);
+
+       return req;
+}
+
+bool add_reqid_mapping(struct pcc_state *pcc_state, struct path *path)
+{
+       struct req_map_data *mapping;
+       mapping = XCALLOC(MTYPE_PCEP, sizeof(*mapping));
+       mapping->nbkey = path->nbkey;
+       mapping->reqid = path->req_id;
+       if (req_map_add(&pcc_state->req_map, mapping) != NULL) {
+               XFREE(MTYPE_PCEP, mapping);
+               return false;
+       }
+       return true;
+}
+
+void remove_reqid_mapping(struct pcc_state *pcc_state, struct path *path)
+{
+       struct req_map_data key, *mapping;
+       key.nbkey = path->nbkey;
+       mapping = req_map_find(&pcc_state->req_map, &key);
+       if (mapping != NULL) {
+               req_map_del(&pcc_state->req_map, mapping);
+               XFREE(MTYPE_PCEP, mapping);
+       }
+}
+
+uint32_t lookup_reqid(struct pcc_state *pcc_state, struct path *path)
+{
+       struct req_map_data key, *mapping;
+       key.nbkey = path->nbkey;
+       mapping = req_map_find(&pcc_state->req_map, &key);
+       if (mapping != NULL)
+               return mapping->reqid;
+       return 0;
+}
+
+bool has_pending_req_for(struct pcc_state *pcc_state, struct path *path)
+{
+       return lookup_reqid(pcc_state, path) != 0;
+}
+
+
+/* ------------ Data Structure Callbacks ------------ */
+
+#define CMP_RETURN(A, B)                                                       \
+       if (A != B)                                                            \
+       return (A < B) ? -1 : 1
+
+static uint32_t hash_nbkey(const struct lsp_nb_key *nbkey)
+{
+       uint32_t hash;
+       hash = jhash_2words(nbkey->color, nbkey->preference, 0x55aa5a5a);
+       switch (nbkey->endpoint.ipa_type) {
+       case IPADDR_V4:
+               return jhash(&nbkey->endpoint.ipaddr_v4,
+                            sizeof(nbkey->endpoint.ipaddr_v4), hash);
+       case IPADDR_V6:
+               return jhash(&nbkey->endpoint.ipaddr_v6,
+                            sizeof(nbkey->endpoint.ipaddr_v6), hash);
+       default:
+               return hash;
+       }
+}
+
+static int cmp_nbkey(const struct lsp_nb_key *a, const struct lsp_nb_key *b)
+{
+       CMP_RETURN(a->color, b->color);
+       int cmp = ipaddr_cmp(&a->endpoint, &b->endpoint);
+       if (cmp != 0)
+               return cmp;
+       CMP_RETURN(a->preference, b->preference);
+       return 0;
+}
+
+int plspid_map_cmp(const struct plspid_map_data *a,
+                  const struct plspid_map_data *b)
+{
+       return cmp_nbkey(&a->nbkey, &b->nbkey);
+}
+
+uint32_t plspid_map_hash(const struct plspid_map_data *e)
+{
+       return hash_nbkey(&e->nbkey);
+}
+
+int nbkey_map_cmp(const struct nbkey_map_data *a,
+                 const struct nbkey_map_data *b)
+{
+       CMP_RETURN(a->plspid, b->plspid);
+       return 0;
+}
+
+uint32_t nbkey_map_hash(const struct nbkey_map_data *e)
+{
+       return e->plspid;
+}
+
+int req_map_cmp(const struct req_map_data *a, const struct req_map_data *b)
+{
+       return cmp_nbkey(&a->nbkey, &b->nbkey);
+}
+
+uint32_t req_map_hash(const struct req_map_data *e)
+{
+       return hash_nbkey(&e->nbkey);
+}
diff --git a/pathd/path_pcep_pcc.h b/pathd/path_pcep_pcc.h
new file mode 100644 (file)
index 0000000..a466d92
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#ifndef _PATH_PCEP_PCC_H_
+#define _PATH_PCEP_PCC_H_
+
+#include "typesafe.h"
+#include "pathd/path_pcep.h"
+
+enum pcc_status {
+       PCEP_PCC_INITIALIZED = 0,
+       PCEP_PCC_DISCONNECTED,
+       PCEP_PCC_CONNECTING,
+       PCEP_PCC_SYNCHRONIZING,
+       PCEP_PCC_OPERATING
+};
+
+PREDECL_HASH(plspid_map)
+PREDECL_HASH(nbkey_map)
+PREDECL_HASH(req_map)
+
+struct plspid_map_data {
+       struct plspid_map_item mi;
+       struct lsp_nb_key nbkey;
+       uint32_t plspid;
+};
+
+struct nbkey_map_data {
+       struct nbkey_map_item mi;
+       struct lsp_nb_key nbkey;
+       uint32_t plspid;
+};
+
+struct req_map_data {
+       struct req_map_item mi;
+       struct lsp_nb_key nbkey;
+       uint32_t reqid;
+};
+
+struct req_entry {
+       RB_ENTRY(req_entry) entry;
+       struct thread *t_retry;
+       int retry_count;
+       bool was_sent;
+       struct path *path;
+};
+RB_HEAD(req_entry_head, req_entry);
+RB_PROTOTYPE(req_entry_head, req_entry, entry, req_entry_compare);
+
+struct pcc_state {
+       int id;
+       char tag[MAX_TAG_SIZE];
+       enum pcc_status status;
+       uint16_t flags;
+#define F_PCC_STATE_HAS_IPV4 0x0002
+#define F_PCC_STATE_HAS_IPV6 0x0004
+       struct pcc_opts *pcc_opts;
+       struct pce_opts *pce_opts;
+       struct in_addr pcc_addr_v4;
+       struct in6_addr pcc_addr_v6;
+       /* PCC transport source address */
+       struct ipaddr pcc_addr_tr;
+       char *originator;
+       pcep_session *sess;
+       uint32_t retry_count;
+       bool synchronized;
+       struct thread *t_reconnect;
+       struct thread *t_update_best;
+       struct thread *t_session_timeout;
+       uint32_t next_reqid;
+       uint32_t next_plspid;
+       struct plspid_map_head plspid_map;
+       struct nbkey_map_head nbkey_map;
+       struct req_map_head req_map;
+       struct req_entry_head requests;
+       struct pcep_caps caps;
+       bool is_best;
+       bool previous_best;
+};
+
+struct pcc_state *pcep_pcc_initialize(struct ctrl_state *ctrl_state,
+                                     int pcc_id);
+void pcep_pcc_finalize(struct ctrl_state *ctrl_state,
+                      struct pcc_state *pcc_state);
+int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state);
+int pcep_pcc_disable(struct ctrl_state *ctrl_state,
+                    struct pcc_state *pcc_state);
+int pcep_pcc_update(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state,
+                   struct pcc_opts *pcc_opts, struct pce_opts *pce_opts);
+void pcep_pcc_reconnect(struct ctrl_state *ctrl_state,
+                       struct pcc_state *pcc_state);
+void pcep_pcc_pcep_event_handler(struct ctrl_state *ctrl_state,
+                                struct pcc_state *pcc_state,
+                                pcep_event *event);
+void pcep_pcc_pathd_event_handler(struct ctrl_state *ctrl_state,
+                                 struct pcc_state *pcc_state,
+                                 enum pcep_pathd_event_type type,
+                                 struct path *path);
+void pcep_pcc_timeout_handler(struct ctrl_state *ctrl_state,
+                             struct pcc_state *pcc_state,
+                             enum pcep_ctrl_timer_type type, void *param);
+void pcep_pcc_sync_path(struct ctrl_state *ctrl_state,
+                       struct pcc_state *pcc_state, struct path *path);
+void pcep_pcc_sync_done(struct ctrl_state *ctrl_state,
+                       struct pcc_state *pcc_state);
+void pcep_pcc_send_report(struct ctrl_state *ctrl_state,
+                         struct pcc_state *pcc_state, struct path *path);
+int pcep_pcc_multi_pce_sync_path(struct ctrl_state *ctrl_state, int pcc_id,
+                                struct pcc_state **pcc_state_list);
+int pcep_pcc_multi_pce_remove_pcc(struct ctrl_state *ctrl_state,
+                                 struct pcc_state **pcc_state_list);
+int pcep_pcc_timer_update_best_pce(struct ctrl_state *ctrl_state, int pcc_id);
+int pcep_pcc_calculate_best_pce(struct pcc_state **pcc);
+int pcep_pcc_get_pcc_id_by_ip_port(struct pcc_state **pcc,
+                                  struct pce_opts *pce_opts);
+int pcep_pcc_get_pcc_id_by_idx(struct pcc_state **pcc, int idx);
+struct pcc_state *pcep_pcc_get_pcc_by_id(struct pcc_state **pcc, int id);
+struct pcc_state *pcep_pcc_get_pcc_by_name(struct pcc_state **pcc,
+                                          const char *pce_name);
+int pcep_pcc_get_pcc_idx_by_id(struct pcc_state **pcc, int id);
+int pcep_pcc_get_free_pcc_idx(struct pcc_state **pcc);
+int pcep_pcc_get_pcc_id(struct pcc_state *pcc);
+void pcep_pcc_copy_pcc_info(struct pcc_state **pcc,
+                           struct pcep_pcc_info *pcc_info);
+
+#endif // _PATH_PCEP_PCC_H_
diff --git a/pathd/path_zebra.c b/pathd/path_zebra.c
new file mode 100644 (file)
index 0000000..276bc92
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#include "thread.h"
+#include "log.h"
+#include "lib_errors.h"
+#include "if.h"
+#include "prefix.h"
+#include "zclient.h"
+#include "network.h"
+#include "stream.h"
+#include "linklist.h"
+#include "nexthop.h"
+#include "vrf.h"
+#include "typesafe.h"
+
+#include "pathd/pathd.h"
+#include "pathd/path_zebra.h"
+
+static struct zclient *zclient;
+static struct zclient *zclient_sync;
+
+/* Global Variables */
+bool g_has_router_id_v4 = false;
+bool g_has_router_id_v6 = false;
+struct in_addr g_router_id_v4;
+struct in6_addr g_router_id_v6;
+pthread_mutex_t g_router_id_v4_mtx = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t g_router_id_v6_mtx = PTHREAD_MUTEX_INITIALIZER;
+
+/**
+ * Gives the IPv4 router ID received from Zebra.
+ *
+ * @param router_id The in_addr strucure where to store the router id
+ * @return true if the router ID was available, false otherwise
+ */
+bool get_ipv4_router_id(struct in_addr *router_id)
+{
+       bool retval = false;
+       assert(router_id != NULL);
+       pthread_mutex_lock(&g_router_id_v4_mtx);
+       if (g_has_router_id_v4) {
+               memcpy(router_id, &g_router_id_v4, sizeof(*router_id));
+               retval = true;
+       }
+       pthread_mutex_unlock(&g_router_id_v4_mtx);
+       return retval;
+}
+
+/**
+ * Gives the IPv6 router ID received from Zebra.
+ *
+ * @param router_id The in6_addr strucure where to store the router id
+ * @return true if the router ID was available, false otherwise
+ */
+bool get_ipv6_router_id(struct in6_addr *router_id)
+{
+       bool retval = false;
+       assert(router_id != NULL);
+       pthread_mutex_lock(&g_router_id_v6_mtx);
+       if (g_has_router_id_v6) {
+               memcpy(router_id, &g_router_id_v6, sizeof(*router_id));
+               retval = true;
+       }
+       pthread_mutex_unlock(&g_router_id_v6_mtx);
+       return retval;
+}
+
+static void path_zebra_connected(struct zclient *zclient)
+{
+       struct srte_policy *policy;
+
+       zclient_send_reg_requests(zclient, VRF_DEFAULT);
+       zclient_send_router_id_update(zclient, ZEBRA_ROUTER_ID_ADD, AFI_IP6,
+                                     VRF_DEFAULT);
+
+       RB_FOREACH (policy, srte_policy_head, &srte_policies) {
+               struct srte_candidate *candidate;
+               struct srte_segment_list *segment_list;
+
+               candidate = policy->best_candidate;
+               if (!candidate)
+                       continue;
+
+               segment_list = candidate->lsp->segment_list;
+               if (!segment_list)
+                       continue;
+
+               path_zebra_add_sr_policy(policy, segment_list);
+       }
+}
+
+static int path_zebra_sr_policy_notify_status(ZAPI_CALLBACK_ARGS)
+{
+       struct zapi_sr_policy zapi_sr_policy;
+       struct srte_policy *policy;
+       struct srte_candidate *best_candidate_path;
+
+       if (zapi_sr_policy_notify_status_decode(zclient->ibuf, &zapi_sr_policy))
+               return -1;
+
+       policy = srte_policy_find(zapi_sr_policy.color,
+                                 &zapi_sr_policy.endpoint);
+       if (!policy)
+               return -1;
+
+       best_candidate_path = policy->best_candidate;
+       if (!best_candidate_path)
+               return -1;
+
+       srte_candidate_status_update(best_candidate_path,
+                                    zapi_sr_policy.status);
+
+       return 0;
+}
+
+/* Router-id update message from zebra. */
+static int path_zebra_router_id_update(ZAPI_CALLBACK_ARGS)
+{
+       struct prefix pref;
+       const char *family;
+       char buf[PREFIX2STR_BUFFER];
+       zebra_router_id_update_read(zclient->ibuf, &pref);
+       if (pref.family == AF_INET) {
+               pthread_mutex_lock(&g_router_id_v4_mtx);
+               memcpy(&g_router_id_v4, &pref.u.prefix4,
+                      sizeof(g_router_id_v4));
+               g_has_router_id_v4 = true;
+               inet_ntop(AF_INET, &g_router_id_v4, buf, sizeof(buf));
+               pthread_mutex_unlock(&g_router_id_v4_mtx);
+               family = "IPv4";
+       } else if (pref.family == AF_INET6) {
+               pthread_mutex_lock(&g_router_id_v6_mtx);
+               memcpy(&g_router_id_v6, &pref.u.prefix6,
+                      sizeof(g_router_id_v6));
+               g_has_router_id_v6 = true;
+               inet_ntop(AF_INET6, &g_router_id_v6, buf, sizeof(buf));
+               pthread_mutex_unlock(&g_router_id_v6_mtx);
+               family = "IPv6";
+       } else {
+               zlog_warn("Unexpected router ID address family for vrf %u: %u",
+                         vrf_id, pref.family);
+               return 0;
+       }
+       zlog_info("%s Router Id updated for VRF %u: %s", family, vrf_id, buf);
+       return 0;
+}
+
+/**
+ * Adds a segment routing policy to Zebra.
+ *
+ * @param policy The policy to add
+ * @param segment_list The segment list for the policy
+ */
+void path_zebra_add_sr_policy(struct srte_policy *policy,
+                             struct srte_segment_list *segment_list)
+{
+       struct zapi_sr_policy zp = {};
+       struct srte_segment_entry *segment;
+
+       zp.color = policy->color;
+       zp.endpoint = policy->endpoint;
+       strlcpy(zp.name, policy->name, sizeof(zp.name));
+       zp.segment_list.type = ZEBRA_LSP_SRTE;
+       zp.segment_list.local_label = policy->binding_sid;
+       zp.segment_list.label_num = 0;
+       RB_FOREACH (segment, srte_segment_entry_head, &segment_list->segments)
+               zp.segment_list.labels[zp.segment_list.label_num++] =
+                       segment->sid_value;
+       policy->status = SRTE_POLICY_STATUS_GOING_UP;
+
+       (void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_SET, &zp);
+}
+
+/**
+ * Deletes a segment policy from Zebra.
+ *
+ * @param policy The policy to remove
+ */
+void path_zebra_delete_sr_policy(struct srte_policy *policy)
+{
+       struct zapi_sr_policy zp = {};
+
+       zp.color = policy->color;
+       zp.endpoint = policy->endpoint;
+       strlcpy(zp.name, policy->name, sizeof(zp.name));
+       zp.segment_list.type = ZEBRA_LSP_SRTE;
+       zp.segment_list.local_label = policy->binding_sid;
+       zp.segment_list.label_num = 0;
+       policy->status = SRTE_POLICY_STATUS_DOWN;
+
+       (void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_DELETE, &zp);
+}
+
+/**
+ * Allocates a label from Zebra's label manager.
+ *
+ * @param label the label to be allocated
+ * @return 0 if the label has been allocated, -1 otherwise
+ */
+int path_zebra_request_label(mpls_label_t label)
+{
+       int ret;
+       uint32_t start, end;
+
+       ret = lm_get_label_chunk(zclient_sync, 0, label, 1, &start, &end);
+       if (ret < 0) {
+               zlog_warn("%s: error getting label range!", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * Releases a previously allocated label from Zebra's label manager.
+ *
+ * @param label The label to release
+ * @return 0 ifthe label has beel released, -1 otherwise
+ */
+void path_zebra_release_label(mpls_label_t label)
+{
+       int ret;
+
+       ret = lm_release_label_chunk(zclient_sync, label, label);
+       if (ret < 0)
+               zlog_warn("%s: error releasing label range!", __func__);
+}
+
+static void path_zebra_label_manager_connect(void)
+{
+       /* Connect to label manager. */
+       while (zclient_socket_connect(zclient_sync) < 0) {
+               zlog_warn("%s: error connecting synchronous zclient!",
+                         __func__);
+               sleep(1);
+       }
+       set_nonblocking(zclient_sync->sock);
+
+       /* Send hello to notify zebra this is a synchronous client */
+       while (zclient_send_hello(zclient_sync) < 0) {
+               zlog_warn("%s: Error sending hello for synchronous zclient!",
+                         __func__);
+               sleep(1);
+       }
+
+       while (lm_label_manager_connect(zclient_sync, 0) != 0) {
+               zlog_warn("%s: error connecting to label manager!", __func__);
+               sleep(1);
+       }
+}
+
+/**
+ * Initializes Zebra asynchronous connection.
+ *
+ * @param master The master thread
+ */
+void path_zebra_init(struct thread_master *master)
+{
+       struct zclient_options options = zclient_options_default;
+       options.synchronous = true;
+
+       /* Initialize asynchronous zclient. */
+       zclient = zclient_new(master, &zclient_options_default);
+       zclient_init(zclient, ZEBRA_ROUTE_SRTE, 0, &pathd_privs);
+       zclient->zebra_connected = path_zebra_connected;
+       zclient->sr_policy_notify_status = path_zebra_sr_policy_notify_status;
+       zclient->router_id_update = path_zebra_router_id_update;
+
+       /* Initialize special zclient for synchronous message exchanges. */
+       zclient_sync = zclient_new(master, &options);
+       zclient_sync->sock = -1;
+       zclient_sync->redist_default = ZEBRA_ROUTE_SRTE;
+       zclient_sync->instance = 1;
+       zclient_sync->privs = &pathd_privs;
+
+       /* Connect to the LM. */
+       path_zebra_label_manager_connect();
+}
diff --git a/pathd/path_zebra.h b/pathd/path_zebra.h
new file mode 100644 (file)
index 0000000..42a7123
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#ifndef _FRR_PATH_MPLS_H_
+#define _FRR_PATH_MPLS_H_
+
+#include <zebra.h>
+#include "pathd/pathd.h"
+
+bool get_ipv4_router_id(struct in_addr *router_id);
+bool get_ipv6_router_id(struct in6_addr *router_id);
+void path_zebra_add_sr_policy(struct srte_policy *policy,
+                             struct srte_segment_list *segment_list);
+void path_zebra_delete_sr_policy(struct srte_policy *policy);
+int path_zebra_request_label(mpls_label_t label);
+void path_zebra_release_label(mpls_label_t label);
+void path_zebra_init(struct thread_master *master);
+
+#endif /* _FRR_PATH_MPLS_H_ */
diff --git a/pathd/pathd.c b/pathd/pathd.c
new file mode 100644 (file)
index 0000000..e2c7c95
--- /dev/null
@@ -0,0 +1,1128 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "log.h"
+#include "lib_errors.h"
+#include "network.h"
+
+#include "pathd/pathd.h"
+#include "pathd/path_memory.h"
+#include "pathd/path_zebra.h"
+#include "pathd/path_debug.h"
+
+#define HOOK_DELAY 3
+
+DEFINE_MTYPE_STATIC(PATHD, PATH_SEGMENT_LIST, "Segment List")
+DEFINE_MTYPE_STATIC(PATHD, PATH_SR_POLICY, "SR Policy")
+DEFINE_MTYPE_STATIC(PATHD, PATH_SR_CANDIDATE, "SR Policy candidate path")
+
+DEFINE_HOOK(pathd_candidate_created, (struct srte_candidate * candidate),
+           (candidate))
+DEFINE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate),
+           (candidate))
+DEFINE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
+           (candidate))
+
+static void trigger_pathd_candidate_created(struct srte_candidate *candidate);
+static int trigger_pathd_candidate_created_timer(struct thread *thread);
+static void trigger_pathd_candidate_updated(struct srte_candidate *candidate);
+static int trigger_pathd_candidate_updated_timer(struct thread *thread);
+static void trigger_pathd_candidate_removed(struct srte_candidate *candidate);
+static const char *
+srte_candidate_metric_name(enum srte_candidate_metric_type type);
+
+static void srte_set_metric(struct srte_metric *metric, float value,
+                           bool required, bool is_bound, bool is_computed);
+static void srte_unset_metric(struct srte_metric *metric);
+
+
+/* Generate rb-tree of Segment List Segment instances. */
+static inline int srte_segment_entry_compare(const struct srte_segment_entry *a,
+                                            const struct srte_segment_entry *b)
+{
+       return a->index - b->index;
+}
+RB_GENERATE(srte_segment_entry_head, srte_segment_entry, entry,
+           srte_segment_entry_compare)
+
+/* Generate rb-tree of Segment List instances. */
+static inline int srte_segment_list_compare(const struct srte_segment_list *a,
+                                           const struct srte_segment_list *b)
+{
+       return strcmp(a->name, b->name);
+}
+RB_GENERATE(srte_segment_list_head, srte_segment_list, entry,
+           srte_segment_list_compare)
+
+struct srte_segment_list_head srte_segment_lists =
+       RB_INITIALIZER(&srte_segment_lists);
+
+/* Generate rb-tree of Candidate Path instances. */
+static inline int srte_candidate_compare(const struct srte_candidate *a,
+                                        const struct srte_candidate *b)
+{
+       return a->preference - b->preference;
+}
+RB_GENERATE(srte_candidate_head, srte_candidate, entry, srte_candidate_compare)
+
+/* Generate rb-tree of SR Policy instances. */
+static inline int srte_policy_compare(const struct srte_policy *a,
+                                     const struct srte_policy *b)
+{
+       return sr_policy_compare(&a->endpoint, &b->endpoint, a->color,
+                                b->color);
+}
+RB_GENERATE(srte_policy_head, srte_policy, entry, srte_policy_compare)
+
+struct srte_policy_head srte_policies = RB_INITIALIZER(&srte_policies);
+
+/**
+ * Adds a segment list to pathd.
+ *
+ * @param name The name of the segment list to add
+ * @return The added segment list
+ */
+struct srte_segment_list *srte_segment_list_add(const char *name)
+{
+       struct srte_segment_list *segment_list;
+
+       segment_list = XCALLOC(MTYPE_PATH_SEGMENT_LIST, sizeof(*segment_list));
+       strlcpy(segment_list->name, name, sizeof(segment_list->name));
+       RB_INIT(srte_segment_entry_head, &segment_list->segments);
+       RB_INSERT(srte_segment_list_head, &srte_segment_lists, segment_list);
+
+       return segment_list;
+}
+
+/**
+ * Deletes a segment list from pathd.
+ *
+ * The given segment list structure will be freed and should not be used anymore
+ * after calling this function.
+ *
+ * @param segment_list the segment list to remove from pathd.
+ */
+void srte_segment_list_del(struct srte_segment_list *segment_list)
+{
+       struct srte_segment_entry *segment, *safe_seg;
+       RB_FOREACH_SAFE (segment, srte_segment_entry_head,
+                        &segment_list->segments, safe_seg) {
+               srte_segment_entry_del(segment);
+       }
+       RB_REMOVE(srte_segment_list_head, &srte_segment_lists, segment_list);
+       XFREE(MTYPE_PATH_SEGMENT_LIST, segment_list);
+}
+
+/**
+ * Search for a segment list by name.
+ *
+ * @param name The name of the segment list to look for
+ * @return The segment list if found, NULL otherwise
+ */
+struct srte_segment_list *srte_segment_list_find(const char *name)
+{
+       struct srte_segment_list search;
+
+       strlcpy(search.name, name, sizeof(search.name));
+       return RB_FIND(srte_segment_list_head, &srte_segment_lists, &search);
+}
+
+/**
+ * Adds a segment to a segment list.
+ *
+ * @param segment_list The segment list the segment should be added to
+ * @param index        The index of the added segment in the segment list
+ * @return The added segment
+ */
+struct srte_segment_entry *
+srte_segment_entry_add(struct srte_segment_list *segment_list, uint32_t index)
+{
+       struct srte_segment_entry *segment;
+
+       segment = XCALLOC(MTYPE_PATH_SEGMENT_LIST, sizeof(*segment));
+       segment->segment_list = segment_list;
+       segment->index = index;
+       RB_INSERT(srte_segment_entry_head, &segment_list->segments, segment);
+
+       return segment;
+}
+
+/**
+ * Deletes a segment from a segment list.
+ *
+ * @param segment The segment to be removed
+ */
+void srte_segment_entry_del(struct srte_segment_entry *segment)
+{
+       RB_REMOVE(srte_segment_entry_head, &segment->segment_list->segments,
+                 segment);
+       XFREE(MTYPE_PATH_SEGMENT_LIST, segment);
+}
+
+/**
+ * Set the node or adjacency identifier of a segment.
+ *
+ * @param segment The segment for which the NAI should be set
+ * @param type The type of the NAI
+ * @param type The address of the node or the local address of the adjacency
+ * @param type The local interface index of the unumbered adjacency
+ * @param type The remote address of the adjacency
+ * @param type The remote interface index of the unumbered adjacency
+ */
+void srte_segment_entry_set_nai(struct srte_segment_entry *segment,
+                               enum srte_segment_nai_type type,
+                               struct ipaddr *local_ip, uint32_t local_iface,
+                               struct ipaddr *remote_ip, uint32_t remote_iface)
+{
+       segment->nai_type = type;
+       memcpy(&segment->nai_local_addr, local_ip, sizeof(struct ipaddr));
+
+       switch (type) {
+       case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
+       case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
+               break;
+       case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
+       case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
+               memcpy(&segment->nai_remote_addr, remote_ip,
+                      sizeof(struct ipaddr));
+               break;
+       case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
+               memcpy(&segment->nai_remote_addr, remote_ip,
+                      sizeof(struct ipaddr));
+               segment->nai_local_iface = local_iface;
+               segment->nai_remote_iface = remote_iface;
+               break;
+       default:
+               segment->nai_local_addr.ipa_type = IPADDR_NONE;
+               segment->nai_local_iface = 0;
+               segment->nai_remote_addr.ipa_type = IPADDR_NONE;
+               segment->nai_remote_iface = 0;
+       }
+}
+
+/**
+ * Add a policy to pathd.
+ *
+ * WARNING: The color 0 is a special case as it is the no-color.
+ *
+ * @param color The color of the policy.
+ * @param endpoint The IP address of the policy endpoint
+ * @return The created policy
+ */
+struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint)
+{
+       struct srte_policy *policy;
+
+       policy = XCALLOC(MTYPE_PATH_SR_POLICY, sizeof(*policy));
+       policy->color = color;
+       policy->endpoint = *endpoint;
+       policy->binding_sid = MPLS_LABEL_NONE;
+       RB_INIT(srte_candidate_head, &policy->candidate_paths);
+       RB_INSERT(srte_policy_head, &srte_policies, policy);
+
+       return policy;
+}
+
+/**
+ * Delete a policy from pathd.
+ *
+ * The given policy structure will be freed and should never be used again
+ * after calling this function.
+ *
+ * @param policy The policy to be removed
+ */
+void srte_policy_del(struct srte_policy *policy)
+{
+       struct srte_candidate *candidate;
+
+       path_zebra_delete_sr_policy(policy);
+
+       path_zebra_release_label(policy->binding_sid);
+
+       while (!RB_EMPTY(srte_candidate_head, &policy->candidate_paths)) {
+               candidate =
+                       RB_ROOT(srte_candidate_head, &policy->candidate_paths);
+               trigger_pathd_candidate_removed(candidate);
+               srte_candidate_del(candidate);
+       }
+
+       RB_REMOVE(srte_policy_head, &srte_policies, policy);
+       XFREE(MTYPE_PATH_SR_POLICY, policy);
+}
+
+/**
+ * Search for a policy by color and endpoint.
+ *
+ * WARNING: The color 0 is a special case as it is the no-color.
+ *
+ * @param color The color of the policy to look for
+ * @param endpoint The endpoint of the policy to look for
+ * @return The policy if found, NULL otherwise
+ */
+struct srte_policy *srte_policy_find(uint32_t color, struct ipaddr *endpoint)
+{
+       struct srte_policy search;
+
+       search.color = color;
+       search.endpoint = *endpoint;
+       return RB_FIND(srte_policy_head, &srte_policies, &search);
+}
+
+/**
+ * Update a policy binding SID.
+ *
+ * @param policy The policy for which the SID should be updated
+ * @param binding_sid The new binding SID for the given policy
+ */
+void srte_policy_update_binding_sid(struct srte_policy *policy,
+                                   uint32_t binding_sid)
+{
+       if (policy->binding_sid != MPLS_LABEL_NONE)
+               path_zebra_release_label(policy->binding_sid);
+
+       policy->binding_sid = binding_sid;
+
+       /* Reinstall the Binding-SID if necessary. */
+       if (policy->best_candidate)
+               path_zebra_add_sr_policy(
+                       policy, policy->best_candidate->lsp->segment_list);
+}
+
+/**
+ * Gives the policy best candidate path.
+ *
+ * @param policy The policy we want the best candidate path from
+ * @return The best candidate path
+ */
+static struct srte_candidate *
+srte_policy_best_candidate(const struct srte_policy *policy)
+{
+       struct srte_candidate *candidate;
+
+       RB_FOREACH_REVERSE (candidate, srte_candidate_head,
+                           &policy->candidate_paths) {
+               /* search for highest preference with existing segment list */
+               if (!CHECK_FLAG(candidate->flags, F_CANDIDATE_DELETED)
+                   && candidate->lsp->segment_list)
+                       return candidate;
+       }
+
+       return NULL;
+}
+
+/**
+ * Apply changes defined by setting the policies, candidate paths
+ * and segment lists modification flags NEW, MODIFIED and DELETED.
+ *
+ * This allows the northbound code to delay all the side effects of adding
+ * modifying and deleting them to the end.
+ *
+ * Example of marking an object as modified:
+ *   `SET_FLAG(obj->flags, F_XXX_MODIFIED)`
+ */
+void srte_apply_changes(void)
+{
+       struct srte_policy *policy, *safe_pol;
+       struct srte_segment_list *segment_list, *safe_sl;
+
+       RB_FOREACH_SAFE (policy, srte_policy_head, &srte_policies, safe_pol) {
+               if (CHECK_FLAG(policy->flags, F_POLICY_DELETED)) {
+                       srte_policy_del(policy);
+                       continue;
+               }
+               srte_policy_apply_changes(policy);
+               UNSET_FLAG(policy->flags, F_POLICY_NEW);
+               UNSET_FLAG(policy->flags, F_POLICY_MODIFIED);
+       }
+
+       RB_FOREACH_SAFE (segment_list, srte_segment_list_head,
+                        &srte_segment_lists, safe_sl) {
+               if (CHECK_FLAG(segment_list->flags, F_SEGMENT_LIST_DELETED)) {
+                       srte_segment_list_del(segment_list);
+                       continue;
+               }
+               UNSET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
+               UNSET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
+       }
+}
+
+/**
+ * Apply changes defined by setting the given policy and its candidate paths
+ * modification flags NEW, MODIFIED and DELETED.
+ *
+ * In moste cases `void srte_apply_changes(void)` should be used instead,
+ * this function will not handle the changes of segment lists used by the
+ * policy.
+ *
+ * @param policy The policy changes has to be applied to.
+ */
+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];
+
+       ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
+
+       /* Get old and new best candidate path. */
+       old_best_candidate = policy->best_candidate;
+       new_best_candidate = srte_policy_best_candidate(policy);
+
+       if (new_best_candidate != old_best_candidate) {
+               /* TODO: add debug guard. */
+               zlog_debug(
+                       "SR-TE(%s, %u): best candidate changed from %s to %s",
+                       endpoint, policy->color,
+                       old_best_candidate ? old_best_candidate->name : "none",
+                       new_best_candidate ? new_best_candidate->name : "none");
+
+               if (old_best_candidate) {
+                       policy->best_candidate = NULL;
+                       UNSET_FLAG(old_best_candidate->flags, F_CANDIDATE_BEST);
+                       SET_FLAG(old_best_candidate->flags,
+                                F_CANDIDATE_MODIFIED);
+
+                       /*
+                        * Rely on replace semantics if there's a new best
+                        * candidate.
+                        */
+                       if (!new_best_candidate)
+                               path_zebra_delete_sr_policy(policy);
+               }
+               if (new_best_candidate) {
+                       policy->best_candidate = new_best_candidate;
+                       SET_FLAG(new_best_candidate->flags, F_CANDIDATE_BEST);
+                       SET_FLAG(new_best_candidate->flags,
+                                F_CANDIDATE_MODIFIED);
+
+                       path_zebra_add_sr_policy(
+                               policy, new_best_candidate->lsp->segment_list);
+               }
+       } else if (new_best_candidate) {
+               /* The best candidate path did not change, but some of its
+                * attributes or its segment list may have changed.
+                */
+
+               bool candidate_changed = CHECK_FLAG(new_best_candidate->flags,
+                                                   F_CANDIDATE_MODIFIED);
+               bool segment_list_changed =
+                       new_best_candidate->lsp->segment_list
+                       && CHECK_FLAG(
+                                  new_best_candidate->lsp->segment_list->flags,
+                                  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_zebra_add_sr_policy(
+                               policy, new_best_candidate->lsp->segment_list);
+               }
+       }
+
+       RB_FOREACH_SAFE (candidate, srte_candidate_head,
+                        &policy->candidate_paths, safe) {
+               if (CHECK_FLAG(candidate->flags, F_CANDIDATE_DELETED)) {
+                       trigger_pathd_candidate_removed(candidate);
+                       srte_candidate_del(candidate);
+                       continue;
+               } else if (CHECK_FLAG(candidate->flags, F_CANDIDATE_NEW)) {
+                       trigger_pathd_candidate_created(candidate);
+               } else if (CHECK_FLAG(candidate->flags, F_CANDIDATE_MODIFIED)) {
+                       trigger_pathd_candidate_updated(candidate);
+               } else if (candidate->lsp->segment_list
+                          && CHECK_FLAG(candidate->lsp->segment_list->flags,
+                                        F_SEGMENT_LIST_MODIFIED)) {
+                       trigger_pathd_candidate_updated(candidate);
+               }
+
+               UNSET_FLAG(candidate->flags, F_CANDIDATE_NEW);
+               UNSET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
+       }
+}
+
+/**
+ * Adds a candidate path to a policy.
+ *
+ * @param policy The policy the candidate path should be added to
+ * @param preference The preference of the candidate path to be added
+ * @return The added candidate path
+ */
+struct srte_candidate *srte_candidate_add(struct srte_policy *policy,
+                                         uint32_t preference)
+{
+       struct srte_candidate *candidate;
+       struct srte_lsp *lsp;
+
+       candidate = XCALLOC(MTYPE_PATH_SR_CANDIDATE, sizeof(*candidate));
+       lsp = XCALLOC(MTYPE_PATH_SR_CANDIDATE, sizeof(*lsp));
+
+       candidate->preference = preference;
+       candidate->policy = policy;
+       candidate->type = SRTE_CANDIDATE_TYPE_UNDEFINED;
+       candidate->discriminator = frr_weak_random();
+
+       lsp->candidate = candidate;
+       candidate->lsp = lsp;
+
+       RB_INSERT(srte_candidate_head, &policy->candidate_paths, candidate);
+
+       return candidate;
+}
+
+/**
+ * Deletes a candidate.
+ *
+ * The corresponding LSP will be removed alongside the candidate path.
+ * The given candidate will be freed and shouldn't be used anymore after the
+ * calling this function.
+ *
+ * @param candidate The candidate path to delete
+ */
+void srte_candidate_del(struct srte_candidate *candidate)
+{
+       struct srte_policy *srte_policy = candidate->policy;
+
+       RB_REMOVE(srte_candidate_head, &srte_policy->candidate_paths,
+                 candidate);
+
+       XFREE(MTYPE_PATH_SR_CANDIDATE, candidate->lsp);
+       XFREE(MTYPE_PATH_SR_CANDIDATE, candidate);
+}
+
+/**
+ * Sets the bandwidth constraint of given candidate path.
+ *
+ * The corresponding LSP will be changed too.
+ *
+ * @param candidate The candidate path of which the bandwidth should be changed
+ * @param bandwidth The Bandwidth constraint to set to the candidate path
+ * @param required If the constraint is required (true) or only desired (false)
+ */
+void srte_candidate_set_bandwidth(struct srte_candidate *candidate,
+                                 float bandwidth, bool required)
+{
+       struct srte_policy *policy = candidate->policy;
+       char endpoint[46];
+       ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
+       zlog_debug(
+               "SR-TE(%s, %u): candidate %s %sconfig bandwidth set to %f B/s",
+               endpoint, policy->color, candidate->name,
+               required ? "required " : "", bandwidth);
+       SET_FLAG(candidate->flags, F_CANDIDATE_HAS_BANDWIDTH);
+       COND_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_BANDWIDTH, required);
+       candidate->bandwidth = bandwidth;
+
+       srte_lsp_set_bandwidth(candidate->lsp, bandwidth, required);
+}
+
+/**
+ * Sets the bandwidth constraint of the given LSP.
+ *
+ * The changes will not be shown as part of the running configuration.
+ *
+ * @param lsp The lsp of which the bandwidth should be changed
+ * @param bandwidth The Bandwidth constraint to set to the candidate path
+ * @param required If the constraint is required (true) or only desired (false)
+ */
+void srte_lsp_set_bandwidth(struct srte_lsp *lsp, float bandwidth,
+                           bool required)
+{
+       struct srte_candidate *candidate = lsp->candidate;
+       struct srte_policy *policy = candidate->policy;
+       char endpoint[46];
+       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);
+       SET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
+       COND_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH, required);
+       lsp->bandwidth = bandwidth;
+}
+
+/**
+ * Remove a candidate path bandwidth constraint.
+ *
+ * The corresponding LSP will be changed too.
+ *
+ * @param candidate The candidate path of which the bandwidth should be removed
+ */
+void srte_candidate_unset_bandwidth(struct srte_candidate *candidate)
+{
+       struct srte_policy *policy = candidate->policy;
+       char endpoint[46];
+       ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
+       zlog_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;
+       SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
+       srte_lsp_unset_bandwidth(candidate->lsp);
+}
+
+/**
+ * Remove an LSP bandwidth constraint.
+ *
+ * The changes will not be shown as part of the running configuration.
+ *
+ * @param lsp The lsp of which the bandwidth should be changed
+ */
+void srte_lsp_unset_bandwidth(struct srte_lsp *lsp)
+{
+       struct srte_candidate *candidate = lsp->candidate;
+       struct srte_policy *policy = candidate->policy;
+       char endpoint[46];
+       ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
+       zlog_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);
+       lsp->bandwidth = 0;
+}
+
+/**
+ * Sets a candidate path metric constraint.
+ *
+ * The corresponding LSP will be changed too.
+ *
+ * @param candidate The candidate path of which the metric should be changed
+ * @param type The metric type
+ * @param value The metric value
+ * @param required If the constraint is required (true) or only desired (false)
+ * @param is_bound If the metric is an indicative value or a strict upper bound
+ * @param is_computed If the metric was computed or configured
+ */
+void srte_candidate_set_metric(struct srte_candidate *candidate,
+                              enum srte_candidate_metric_type type,
+                              float value, bool required, bool is_bound,
+                              bool is_computed)
+{
+       struct srte_policy *policy = candidate->policy;
+       char endpoint[46];
+       ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
+       zlog_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),
+               type, value, is_bound ? "true" : "false",
+               is_computed ? "true" : "false");
+       assert((type > 0) && (type <= MAX_METRIC_TYPE));
+       srte_set_metric(&candidate->metrics[type - 1], value, required,
+                       is_bound, is_computed);
+       srte_lsp_set_metric(candidate->lsp, type, value, required, is_bound,
+                           is_computed);
+       SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
+}
+
+/**
+ * Sets an LSP metric constraint.
+ *
+ * The changes will not be shown as part of the running configuration.
+ *
+ * @param lsp The LSP of which the metric should be changed
+ * @param type The metric type
+ * @param value The metric value
+ * @param required If the constraint is required (true) or only desired (false)
+ * @param is_bound If the metric is an indicative value or a strict upper bound
+ * @param is_computed If the metric was computed or configured
+ */
+void srte_lsp_set_metric(struct srte_lsp *lsp,
+                        enum srte_candidate_metric_type type, float value,
+                        bool required, bool is_bound, bool is_computed)
+{
+       struct srte_candidate *candidate = lsp->candidate;
+       struct srte_policy *policy = candidate->policy;
+       char endpoint[46];
+       ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
+       zlog_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),
+               type, value, is_bound ? "true" : "false",
+               is_computed ? "true" : "false");
+       assert((type > 0) && (type <= MAX_METRIC_TYPE));
+       srte_set_metric(&lsp->metrics[type - 1], value, required, is_bound,
+                       is_computed);
+}
+
+void srte_set_metric(struct srte_metric *metric, float value, bool required,
+                    bool is_bound, bool is_computed)
+{
+       SET_FLAG(metric->flags, F_METRIC_IS_DEFINED);
+       COND_FLAG(metric->flags, F_METRIC_IS_REQUIRED, required);
+       COND_FLAG(metric->flags, F_METRIC_IS_BOUND, is_bound);
+       COND_FLAG(metric->flags, F_METRIC_IS_COMPUTED, is_computed);
+       metric->value = value;
+}
+
+/**
+ * Removes a candidate path metric constraint.
+ *
+ * The corresponding LSP will be changed too.
+ *
+ * @param candidate The candidate path from which the metric should be removed
+ * @param type The metric type
+ */
+void srte_candidate_unset_metric(struct srte_candidate *candidate,
+                                enum srte_candidate_metric_type type)
+{
+       struct srte_policy *policy = candidate->policy;
+       char endpoint[46];
+       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);
+       assert((type > 0) && (type <= MAX_METRIC_TYPE));
+       srte_unset_metric(&candidate->metrics[type - 1]);
+       srte_lsp_unset_metric(candidate->lsp, type);
+       SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
+}
+
+/**
+ * Removes a candidate path metric constraint.
+ *
+ * The changes will not be shown as part of the running configuration.
+ *
+ * @param lsp The LSP from which the metric should be removed
+ * @param type The metric type
+ */
+void srte_lsp_unset_metric(struct srte_lsp *lsp,
+                          enum srte_candidate_metric_type type)
+{
+       struct srte_candidate *candidate = lsp->candidate;
+       struct srte_policy *policy = candidate->policy;
+       char endpoint[46];
+       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);
+       assert((type > 0) && (type <= MAX_METRIC_TYPE));
+       srte_unset_metric(&lsp->metrics[type - 1]);
+}
+
+void srte_unset_metric(struct srte_metric *metric)
+{
+       UNSET_FLAG(metric->flags, F_METRIC_IS_DEFINED);
+       UNSET_FLAG(metric->flags, F_METRIC_IS_BOUND);
+       UNSET_FLAG(metric->flags, F_METRIC_IS_COMPUTED);
+       metric->value = 0;
+}
+
+/**
+ * Sets a candidate path objective function.
+ *
+ * @param candidate The candidate path of which the OF should be changed
+ * @param required If the constraint is required (true) or only desired (false)
+ * @param type The objective function type
+ */
+void srte_candidate_set_objfun(struct srte_candidate *candidate, bool required,
+                              enum objfun_type type)
+{
+       struct srte_policy *policy = candidate->policy;
+       char endpoint[46];
+       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));
+}
+
+/**
+ * Removed the objective function constraint from a candidate path.
+ *
+ * @param candidate The candidate path from which the OF should be removed
+ */
+void srte_candidate_unset_objfun(struct srte_candidate *candidate)
+{
+       struct srte_policy *policy = candidate->policy;
+       char endpoint[46];
+       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(
+               "SR-TE(%s, %u): candidate %s objective functions preferences unset",
+               endpoint, policy->color, candidate->name);
+}
+
+static uint32_t filter_type_to_flag(enum affinity_filter_type type)
+{
+       switch (type) {
+       case AFFINITY_FILTER_EXCLUDE_ANY:
+               return F_CANDIDATE_HAS_EXCLUDE_ANY;
+       case AFFINITY_FILTER_INCLUDE_ANY:
+               return F_CANDIDATE_HAS_INCLUDE_ANY;
+       case AFFINITY_FILTER_INCLUDE_ALL:
+               return F_CANDIDATE_HAS_INCLUDE_ALL;
+       default:
+               return 0;
+       }
+}
+
+static const char *filter_type_name(enum affinity_filter_type type)
+{
+       switch (type) {
+       case AFFINITY_FILTER_EXCLUDE_ANY:
+               return "exclude-any";
+       case AFFINITY_FILTER_INCLUDE_ANY:
+               return "include-any";
+       case AFFINITY_FILTER_INCLUDE_ALL:
+               return "include-all";
+       default:
+               return "unknown";
+       }
+}
+
+/**
+ * Sets a candidate path affinity filter constraint.
+ *
+ * @param candidate The candidate path of which the constraint should be changed
+ * @param type The affinity constraint type to set
+ * @param filter The bitmask filter of the constraint
+ */
+void srte_candidate_set_affinity_filter(struct srte_candidate *candidate,
+                                       enum affinity_filter_type type,
+                                       uint32_t filter)
+{
+       struct srte_policy *policy = candidate->policy;
+       char endpoint[46];
+       ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
+
+       assert(type > AFFINITY_FILTER_UNDEFINED);
+       assert(type <= MAX_AFFINITY_FILTER_TYPE);
+       SET_FLAG(candidate->flags, filter_type_to_flag(type));
+       SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
+       candidate->affinity_filters[type - 1] = filter;
+       zlog_debug(
+               "SR-TE(%s, %u): candidate %s affinity filter %s set to 0x%08x",
+               endpoint, policy->color, candidate->name,
+               filter_type_name(type), filter);
+}
+
+/**
+ * Removes a candidate path affinity filter constraint.
+ *
+ * @param candidate The candidate path from which the constraint should be
+ * removed
+ * @param type The affinity constraint type to remove
+ */
+void srte_candidate_unset_affinity_filter(struct srte_candidate *candidate,
+                                         enum affinity_filter_type type)
+{
+       struct srte_policy *policy = candidate->policy;
+       char endpoint[46];
+       ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
+
+       assert(type > AFFINITY_FILTER_UNDEFINED);
+       assert(type <= MAX_AFFINITY_FILTER_TYPE);
+       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));
+}
+
+/**
+ * Searches for a candidate path of the given policy.
+ *
+ * @param policy The policy to search for candidate path
+ * @param preference The preference of the candidate path you are looking for
+ * @return The candidate path if found, NULL otherwise
+ */
+struct srte_candidate *srte_candidate_find(struct srte_policy *policy,
+                                          uint32_t preference)
+{
+       struct srte_candidate search;
+
+       search.preference = preference;
+       return RB_FIND(srte_candidate_head, &policy->candidate_paths, &search);
+}
+
+/**
+ * Searches for a an entry of a given segment list.
+ *
+ * @param segment_list The segment list to search for the entry
+ * @param index The index of the entry you are looking for
+ * @return The segment list entry if found, NULL otherwise.
+ */
+struct srte_segment_entry *
+srte_segment_entry_find(struct srte_segment_list *segment_list, uint32_t index)
+{
+       struct srte_segment_entry search;
+
+       search.index = index;
+       return RB_FIND(srte_segment_entry_head, &segment_list->segments,
+                      &search);
+}
+
+/**
+ * Updates a candidate status.
+ *
+ * @param candidate The candidate of which the status should be updated
+ * @param status The new candidate path status
+ */
+void srte_candidate_status_update(struct srte_candidate *candidate, int status)
+{
+       struct srte_policy *policy = candidate->policy;
+       char endpoint[46];
+       ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
+       zlog_debug("SR-TE(%s, %u): zebra updated status to %d", endpoint,
+                  policy->color, status);
+       switch (status) {
+       case ZEBRA_SR_POLICY_DOWN:
+               switch (policy->status) {
+               /* If the policy is GOING_UP, and zebra faild
+                  to install it, we wait for zebra to retry */
+               /* TODO: Add some timeout after which we would
+                                get is back to DOWN and remove the
+                                policy */
+               case SRTE_POLICY_STATUS_GOING_UP:
+               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;
+                       break;
+               }
+               break;
+       case ZEBRA_SR_POLICY_UP:
+               switch (policy->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;
+                       break;
+               }
+               break;
+       }
+
+       trigger_pathd_candidate_updated(candidate);
+}
+
+/**
+ * Flags the segment lists from give originator for removal.
+ *
+ * The function srte_apply_changes must be called afterward for
+ * the segment list to be removed.
+ *
+ * @param originator The originator tag of the segment list to be marked
+ * @param force If the unset should be forced regardless of the originator
+ */
+void srte_candidate_unset_segment_list(const char *originator, bool force)
+{
+       if (originator == NULL) {
+               zlog_warn(
+                       "Cannot unset segment list because originator is NULL");
+               return;
+       }
+
+       zlog_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);
+               struct srte_candidate *candidate;
+               RB_FOREACH (candidate, srte_candidate_head,
+                           &policy->candidate_paths) {
+                       zlog_debug("Unset segment lists checking candidate %s",
+                                  candidate->name);
+                       if (candidate->lsp == NULL) {
+                               continue;
+                       }
+
+                       /* The candidate->lsp->segment_list is operational data,
+                        * configured by the PCE. We dont want to modify the
+                        * candidate->segment_list,
+                        * which is configuration data. */
+                       struct srte_segment_list *segment_list =
+                               candidate->lsp->segment_list;
+                       if (segment_list == NULL) {
+                               continue;
+                       }
+
+                       if (segment_list->protocol_origin
+                           == SRTE_ORIGIN_LOCAL) {
+                               zlog_warn(
+                                       "Cannot unset segment list %s because it "
+                                       "was created locally",
+                                       segment_list->name);
+                               continue;
+                       }
+
+                       /* In the case of last pce,we force the unset
+                        * because we don't have pce by prefix (TODO) is all
+                        * 'global' */
+                       if (strncmp(segment_list->originator, originator,
+                                   sizeof(segment_list->originator))
+                                   == 0
+                           || force) {
+                               zlog_debug("Unset segment list %s",
+                                          segment_list->name);
+                               SET_FLAG(segment_list->flags,
+                                        F_SEGMENT_LIST_DELETED);
+                               SET_FLAG(candidate->flags,
+                                        F_CANDIDATE_MODIFIED);
+                               candidate->lsp->segment_list = NULL;
+                       }
+               }
+       }
+}
+
+/**
+ * Gives a string representation of given protocol origin enum.
+ *
+ * @param origin The enum you want a string representation of
+ * @return The string representation of given enum
+ */
+const char *srte_origin2str(enum srte_protocol_origin origin)
+{
+       switch (origin) {
+       case SRTE_ORIGIN_PCEP:
+               return "PCEP";
+       case SRTE_ORIGIN_BGP:
+               return "BGP";
+       case SRTE_ORIGIN_LOCAL:
+               return "Local";
+       default:
+               return "Unknown";
+       }
+}
+
+void trigger_pathd_candidate_created(struct srte_candidate *candidate)
+{
+       /* The hook is called asynchronously to let the PCEP module
+       time to send a response to the PCE before receiving any updates from
+       pathd. In addition, a minimum amount of time need to pass before
+       the hook is called to prevent the hook to be called multiple times
+       from changing the candidate by hand with the console */
+       if (candidate->hook_timer != NULL)
+               return;
+       thread_add_timer(master, trigger_pathd_candidate_created_timer,
+                        (void *)candidate, HOOK_DELAY, &candidate->hook_timer);
+}
+
+int trigger_pathd_candidate_created_timer(struct thread *thread)
+{
+       struct srte_candidate *candidate = THREAD_ARG(thread);
+       candidate->hook_timer = NULL;
+       return hook_call(pathd_candidate_created, candidate);
+}
+
+void trigger_pathd_candidate_updated(struct srte_candidate *candidate)
+{
+       /* The hook is called asynchronously to let the PCEP module
+       time to send a response to the PCE before receiving any updates from
+       pathd. In addition, a minimum amount of time need to pass before
+       the hook is called to prevent the hook to be called multiple times
+       from changing the candidate by hand with the console */
+       if (candidate->hook_timer != NULL)
+               return;
+       thread_add_timer(master, trigger_pathd_candidate_updated_timer,
+                        (void *)candidate, HOOK_DELAY, &candidate->hook_timer);
+}
+
+int trigger_pathd_candidate_updated_timer(struct thread *thread)
+{
+       struct srte_candidate *candidate = THREAD_ARG(thread);
+       candidate->hook_timer = NULL;
+       return hook_call(pathd_candidate_updated, candidate);
+}
+
+void trigger_pathd_candidate_removed(struct srte_candidate *candidate)
+{
+       /* The hook needs to be call synchronously, otherwise the candidate
+       path will be already deleted when the handler is called */
+       if (candidate->hook_timer != NULL) {
+               thread_cancel(&candidate->hook_timer);
+               candidate->hook_timer = NULL;
+       }
+       hook_call(pathd_candidate_removed, candidate);
+}
+
+const char *srte_candidate_metric_name(enum srte_candidate_metric_type type)
+{
+       switch (type) {
+       case SRTE_CANDIDATE_METRIC_TYPE_IGP:
+               return "IGP";
+       case SRTE_CANDIDATE_METRIC_TYPE_TE:
+               return "TE";
+       case SRTE_CANDIDATE_METRIC_TYPE_HC:
+               return "HC";
+       case SRTE_CANDIDATE_METRIC_TYPE_ABC:
+               return "ABC";
+       case SRTE_CANDIDATE_METRIC_TYPE_LMLL:
+               return "LMLL";
+       case SRTE_CANDIDATE_METRIC_TYPE_CIGP:
+               return "CIGP";
+       case SRTE_CANDIDATE_METRIC_TYPE_CTE:
+               return "CTE";
+       case SRTE_CANDIDATE_METRIC_TYPE_PIGP:
+               return "PIGP";
+       case SRTE_CANDIDATE_METRIC_TYPE_PTE:
+               return "PTE";
+       case SRTE_CANDIDATE_METRIC_TYPE_PHC:
+               return "PHC";
+       case SRTE_CANDIDATE_METRIC_TYPE_MSD:
+               return "MSD";
+       case SRTE_CANDIDATE_METRIC_TYPE_PD:
+               return "PD";
+       case SRTE_CANDIDATE_METRIC_TYPE_PDV:
+               return "PDV";
+       case SRTE_CANDIDATE_METRIC_TYPE_PL:
+               return "PL";
+       case SRTE_CANDIDATE_METRIC_TYPE_PPD:
+               return "PPD";
+       case SRTE_CANDIDATE_METRIC_TYPE_PPDV:
+               return "PPDV";
+       case SRTE_CANDIDATE_METRIC_TYPE_PPL:
+               return "PPL";
+       case SRTE_CANDIDATE_METRIC_TYPE_NAP:
+               return "NAP";
+       case SRTE_CANDIDATE_METRIC_TYPE_NLP:
+               return "NLP";
+       case SRTE_CANDIDATE_METRIC_TYPE_DC:
+               return "DC";
+       case SRTE_CANDIDATE_METRIC_TYPE_BNC:
+               return "BNC";
+       default:
+               return "UNKNOWN";
+       }
+}
diff --git a/pathd/pathd.conf.sample b/pathd/pathd.conf.sample
new file mode 100644 (file)
index 0000000..9fe7d2d
--- /dev/null
@@ -0,0 +1,41 @@
+! Default pathd configuration sample
+!
+password frr
+log stdout
+
+segment-routing
+ traffic-eng
+  segment-list test1
+   index 10 mpls label 123
+   index 20 mpls label 456
+  !
+  segment-list test2
+   index 10 mpls label 321
+   index 20 mpls label 654
+  !
+  policy color 1 endpoint 1.1.1.1
+   name one
+   binding-sid 100
+   candidate-path preference 100 name test1 explicit segment-list test1
+   candidate-path preference 200 name test2 explicit segment-list test2
+  !
+  policy color 2 endpoint 2.2.2.2
+   name two
+   binding-sid 101
+   candidate-path preference 100 name def explicit segment-list test2
+   candidate-path preference 200 name dyn dynamic
+    bandwidth 12345
+    metric bound abc 16 required
+    metric te 10
+   !
+  !
+  pcep
+   pcc-peer PCE1
+    address ip 127.0.0.1
+    sr-draft07
+   !
+   pcc
+    peer PCE1
+   !
+ !
+!
diff --git a/pathd/pathd.h b/pathd/pathd.h
new file mode 100644 (file)
index 0000000..4879239
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 2020  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
+ */
+
+#ifndef _FRR_PATHD_H_
+#define _FRR_PATHD_H_
+
+#include "lib/mpls.h"
+#include "lib/ipaddr.h"
+#include "lib/srte.h"
+#include "lib/hook.h"
+
+enum srte_protocol_origin {
+       SRTE_ORIGIN_UNDEFINED = 0,
+       SRTE_ORIGIN_PCEP = 1,
+       SRTE_ORIGIN_BGP = 2,
+       SRTE_ORIGIN_LOCAL = 3,
+};
+
+enum srte_policy_status {
+       SRTE_POLICY_STATUS_UNKNOWN = 0,
+       SRTE_POLICY_STATUS_DOWN = 1,
+       SRTE_POLICY_STATUS_UP = 2,
+       SRTE_POLICY_STATUS_GOING_DOWN = 3,
+       SRTE_POLICY_STATUS_GOING_UP = 4
+};
+
+enum srte_candidate_type {
+       SRTE_CANDIDATE_TYPE_UNDEFINED = 0,
+       SRTE_CANDIDATE_TYPE_EXPLICIT = 1,
+       SRTE_CANDIDATE_TYPE_DYNAMIC = 2,
+};
+
+enum srte_candidate_metric_type {
+       /* IGP metric */
+       SRTE_CANDIDATE_METRIC_TYPE_IGP = 1,
+       /* TE metric */
+       SRTE_CANDIDATE_METRIC_TYPE_TE = 2,
+       /* Hop Counts */
+       SRTE_CANDIDATE_METRIC_TYPE_HC = 3,
+       /* Aggregate bandwidth consumption */
+       SRTE_CANDIDATE_METRIC_TYPE_ABC = 4,
+       /* Load of the most loaded link */
+       SRTE_CANDIDATE_METRIC_TYPE_LMLL = 5,
+       /* Cumulative IGP cost */
+       SRTE_CANDIDATE_METRIC_TYPE_CIGP = 6,
+       /* Cumulative TE cost */
+       SRTE_CANDIDATE_METRIC_TYPE_CTE = 7,
+       /* P2MP IGP metric */
+       SRTE_CANDIDATE_METRIC_TYPE_PIGP = 8,
+       /* P2MP TE metric */
+       SRTE_CANDIDATE_METRIC_TYPE_PTE = 9,
+       /* P2MP hop count metric */
+       SRTE_CANDIDATE_METRIC_TYPE_PHC = 10,
+       /* Segment-ID (SID) Depth */
+       SRTE_CANDIDATE_METRIC_TYPE_MSD = 11,
+       /* Path Delay metric */
+       SRTE_CANDIDATE_METRIC_TYPE_PD = 12,
+       /* Path Delay Variation metric */
+       SRTE_CANDIDATE_METRIC_TYPE_PDV = 13,
+       /* Path Loss metric */
+       SRTE_CANDIDATE_METRIC_TYPE_PL = 14,
+       /* P2MP Path Delay metric */
+       SRTE_CANDIDATE_METRIC_TYPE_PPD = 15,
+       /* P2MP Path Delay variation metric */
+       SRTE_CANDIDATE_METRIC_TYPE_PPDV = 16,
+       /* P2MP Path Loss metric */
+       SRTE_CANDIDATE_METRIC_TYPE_PPL = 17,
+       /* Number of adaptations on a path */
+       SRTE_CANDIDATE_METRIC_TYPE_NAP = 18,
+       /* Number of layers on a path */
+       SRTE_CANDIDATE_METRIC_TYPE_NLP = 19,
+       /* Domain Count metric */
+       SRTE_CANDIDATE_METRIC_TYPE_DC = 20,
+       /* Border Node Count metric */
+       SRTE_CANDIDATE_METRIC_TYPE_BNC = 21,
+};
+#define MAX_METRIC_TYPE 21
+
+enum srte_segment_nai_type {
+       SRTE_SEGMENT_NAI_TYPE_NONE = 0,
+       SRTE_SEGMENT_NAI_TYPE_IPV4_NODE = 1,
+       SRTE_SEGMENT_NAI_TYPE_IPV6_NODE = 2,
+       SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY = 3,
+       SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY = 4,
+       SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY = 5
+};
+
+enum objfun_type {
+       OBJFUN_UNDEFINED = 0,
+       /* Minimum Cost Path [RFC5541] */
+       OBJFUN_MCP = 1,
+       /* Minimum Load Path [RFC5541] */
+       OBJFUN_MLP = 2,
+       /* Maximum residual Bandwidth Path [RFC5541] */
+       OBJFUN_MBP = 3,
+       /* Minimize aggregate Bandwidth Consumption [RFC5541] */
+       OBJFUN_MBC = 4,
+       /* Minimize the Load of the most loaded Link [RFC5541] */
+       OBJFUN_MLL = 5,
+       /* Minimize the Cumulative Cost of a set of paths [RFC5541] */
+       OBJFUN_MCC = 6,
+       /* Shortest Path Tree [RFC8306] */
+       OBJFUN_SPT = 7,
+       /* Minimum Cost Tree [RFC8306] */
+       OBJFUN_MCT = 8,
+       /* Minimum Packet Loss Path [RFC8233] */
+       OBJFUN_MPLP = 9,
+       /* Maximum Under-Utilized Path [RFC8233] */
+       OBJFUN_MUP = 10,
+       /* Maximum Reserved Under-Utilized Path [RFC8233] */
+       OBJFUN_MRUP = 11,
+       /* Minimize the number of Transit Domains [RFC8685] */
+       OBJFUN_MTD = 12,
+       /* Minimize the number of Border Nodes [RFC8685] */
+       OBJFUN_MBN = 13,
+       /* Minimize the number of Common Transit Domains [RFC8685] */
+       OBJFUN_MCTD = 14,
+       /* Minimize the number of Shared Links [RFC8800] */
+       OBJFUN_MSL = 15,
+       /* Minimize the number of Shared SRLGs [RFC8800] */
+       OBJFUN_MSS = 16,
+       /* Minimize the number of Shared Nodes [RFC8800] */
+       OBJFUN_MSN = 17,
+};
+#define MAX_OBJFUN_TYPE 17
+
+enum affinity_filter_type {
+       AFFINITY_FILTER_UNDEFINED = 0,
+       AFFINITY_FILTER_EXCLUDE_ANY = 1,
+       AFFINITY_FILTER_INCLUDE_ANY = 2,
+       AFFINITY_FILTER_INCLUDE_ALL = 3,
+};
+#define MAX_AFFINITY_FILTER_TYPE 3
+
+struct srte_segment_list;
+
+struct srte_segment_entry {
+       RB_ENTRY(srte_segment_entry) entry;
+
+       /* The segment list the entry belong to */
+       struct srte_segment_list *segment_list;
+
+       /* Index of the Label. */
+       uint32_t index;
+
+       /* Label Value. */
+       mpls_label_t sid_value;
+
+       /* NAI Type */
+       enum srte_segment_nai_type nai_type;
+       /* NAI local address when nai type is not NONE */
+       struct ipaddr nai_local_addr;
+       /* NAI local interface when nai type is not IPv4 unnumbered adjacency */
+       uint32_t nai_local_iface;
+       /* NAI local interface when nai type is IPv4 or IPv6 adjacency */
+       struct ipaddr nai_remote_addr;
+       /* NAI remote interface when nai type is not IPv4 unnumbered adjacency
+        */
+       uint32_t nai_remote_iface;
+};
+RB_HEAD(srte_segment_entry_head, srte_segment_entry);
+RB_PROTOTYPE(srte_segment_entry_head, srte_segment_entry, entry,
+            srte_segment_entry_compare)
+
+struct srte_segment_list {
+       RB_ENTRY(srte_segment_list) entry;
+
+       /* Name of the Segment List. */
+       char name[64];
+
+       /* The Protocol-Origin. */
+       enum srte_protocol_origin protocol_origin;
+
+       /* The Originator */
+       char originator[64];
+
+       /* Nexthops. */
+       struct srte_segment_entry_head segments;
+
+       /* Status flags. */
+       uint16_t flags;
+#define F_SEGMENT_LIST_NEW 0x0002
+#define F_SEGMENT_LIST_MODIFIED 0x0004
+#define F_SEGMENT_LIST_DELETED 0x0008
+};
+RB_HEAD(srte_segment_list_head, srte_segment_list);
+RB_PROTOTYPE(srte_segment_list_head, srte_segment_list, entry,
+            srte_segment_list_compare)
+
+struct srte_metric {
+       uint16_t flags;
+#define F_METRIC_IS_DEFINED 0x0001
+#define F_METRIC_IS_REQUIRED 0x0002
+#define F_METRIC_IS_BOUND 0x0004
+#define F_METRIC_IS_COMPUTED 0x0008
+       float value;
+};
+
+/* Runtime information about the candidate path */
+struct srte_lsp {
+       /* Backpointer to the Candidate Path. */
+       struct srte_candidate *candidate;
+
+       /* The associated Segment List. */
+       struct srte_segment_list *segment_list;
+
+       /* The Protocol-Origin. */
+       enum srte_protocol_origin protocol_origin;
+
+       /* The Originator */
+       char originator[64];
+
+       /* The Discriminator */
+       uint32_t discriminator;
+
+       /* Flags. */
+       uint32_t flags;
+
+       /* Metrics LSP Values */
+       struct srte_metric metrics[MAX_METRIC_TYPE];
+
+       /* Bandwidth Configured Value */
+       float bandwidth;
+
+       /* The objective function in used */
+       enum objfun_type objfun;
+};
+
+/* Configured candidate path */
+struct srte_candidate {
+       RB_ENTRY(srte_candidate) entry;
+
+       /* Backpointer to SR Policy */
+       struct srte_policy *policy;
+
+       /* The LSP associated with this candidate path. */
+       struct srte_lsp *lsp;
+
+       /* Administrative preference. */
+       uint32_t preference;
+
+       /* Symbolic Name. */
+       char name[64];
+
+       /* The associated Segment List. */
+       struct srte_segment_list *segment_list;
+
+       /* The Protocol-Origin. */
+       enum srte_protocol_origin protocol_origin;
+
+       /* The Originator */
+       char originator[64];
+
+       /* The Discriminator */
+       uint32_t discriminator;
+
+       /* The Type (explicit or dynamic) */
+       enum srte_candidate_type type;
+
+       /* Flags. */
+       uint32_t flags;
+#define F_CANDIDATE_BEST 0x0001
+#define F_CANDIDATE_NEW 0x0002
+#define F_CANDIDATE_MODIFIED 0x0004
+#define F_CANDIDATE_DELETED 0x0008
+#define F_CANDIDATE_HAS_BANDWIDTH 0x0100
+#define F_CANDIDATE_REQUIRED_BANDWIDTH 0x0200
+#define F_CANDIDATE_HAS_OBJFUN 0x0400
+#define F_CANDIDATE_REQUIRED_OBJFUN 0x0800
+#define F_CANDIDATE_HAS_EXCLUDE_ANY 0x1000
+#define F_CANDIDATE_HAS_INCLUDE_ANY 0x2000
+#define F_CANDIDATE_HAS_INCLUDE_ALL 0x4000
+
+       /* Metrics Configured Values */
+       struct srte_metric metrics[MAX_METRIC_TYPE];
+
+       /* Bandwidth Configured Value */
+       float bandwidth;
+
+       /* Configured objective functions */
+       enum objfun_type objfun;
+
+       /* Path constraints attribute filters */
+       uint32_t affinity_filters[MAX_AFFINITY_FILTER_TYPE];
+
+       /* Hooks delaying timer */
+       struct thread *hook_timer;
+};
+
+RB_HEAD(srte_candidate_head, srte_candidate);
+RB_PROTOTYPE(srte_candidate_head, srte_candidate, entry, srte_candidate_compare)
+
+struct srte_policy {
+       RB_ENTRY(srte_policy) entry;
+
+       /* Color */
+       uint32_t color;
+
+       /* Endpoint */
+       struct ipaddr endpoint;
+
+       /* Name */
+       char name[64];
+
+       /* Binding SID */
+       mpls_label_t binding_sid;
+
+       /* Operational Status of the policy */
+       enum srte_policy_status status;
+
+       /* Best candidate path. */
+       struct srte_candidate *best_candidate;
+
+       /* Candidate Paths */
+       struct srte_candidate_head candidate_paths;
+       /* Status flags. */
+       uint16_t flags;
+#define F_POLICY_NEW 0x0002
+#define F_POLICY_MODIFIED 0x0004
+#define F_POLICY_DELETED 0x0008
+};
+RB_HEAD(srte_policy_head, srte_policy);
+RB_PROTOTYPE(srte_policy_head, srte_policy, entry, srte_policy_compare)
+
+DECLARE_HOOK(pathd_candidate_created, (struct srte_candidate * candidate),
+            (candidate))
+DECLARE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate),
+            (candidate))
+DECLARE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
+            (candidate))
+
+extern struct srte_segment_list_head srte_segment_lists;
+extern struct srte_policy_head srte_policies;
+extern struct zebra_privs_t pathd_privs;
+
+/* master thread, defined in path_main.c */
+extern struct thread_master *master;
+
+/* pathd.c */
+struct srte_segment_list *srte_segment_list_add(const char *name);
+void srte_segment_list_del(struct srte_segment_list *segment_list);
+struct srte_segment_list *srte_segment_list_find(const char *name);
+struct srte_segment_entry *
+srte_segment_entry_add(struct srte_segment_list *segment_list, uint32_t index);
+void srte_segment_entry_del(struct srte_segment_entry *segment);
+void srte_segment_entry_set_nai(struct srte_segment_entry *segment,
+                               enum srte_segment_nai_type type,
+                               struct ipaddr *local_ip, uint32_t local_iface,
+                               struct ipaddr *remote_ip,
+                               uint32_t remote_iface);
+struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint);
+void srte_policy_del(struct srte_policy *policy);
+struct srte_policy *srte_policy_find(uint32_t color, struct ipaddr *endpoint);
+void srte_policy_update_binding_sid(struct srte_policy *policy,
+                                   uint32_t binding_sid);
+void srte_apply_changes(void);
+void srte_policy_apply_changes(struct srte_policy *policy);
+struct srte_candidate *srte_candidate_add(struct srte_policy *policy,
+                                         uint32_t preference);
+void srte_candidate_del(struct srte_candidate *candidate);
+void srte_candidate_set_bandwidth(struct srte_candidate *candidate,
+                                 float bandwidth, bool required);
+void srte_candidate_unset_bandwidth(struct srte_candidate *candidate);
+void srte_candidate_set_metric(struct srte_candidate *candidate,
+                              enum srte_candidate_metric_type type,
+                              float value, bool required, bool is_cound,
+                              bool is_computed);
+void srte_candidate_unset_metric(struct srte_candidate *candidate,
+                                enum srte_candidate_metric_type type);
+void srte_candidate_set_objfun(struct srte_candidate *candidate, bool required,
+                              enum objfun_type type);
+void srte_candidate_unset_objfun(struct srte_candidate *candidate);
+void srte_candidate_set_affinity_filter(struct srte_candidate *candidate,
+                                       enum affinity_filter_type type,
+                                       uint32_t filter);
+void srte_candidate_unset_affinity_filter(struct srte_candidate *candidate,
+                                         enum affinity_filter_type type);
+void srte_lsp_set_bandwidth(struct srte_lsp *lsp, float bandwidth,
+                           bool required);
+void srte_lsp_unset_bandwidth(struct srte_lsp *lsp);
+void srte_lsp_set_metric(struct srte_lsp *lsp,
+                        enum srte_candidate_metric_type type, float value,
+                        bool required, bool is_cound, bool is_computed);
+void srte_lsp_unset_metric(struct srte_lsp *lsp,
+                          enum srte_candidate_metric_type type);
+struct srte_candidate *srte_candidate_find(struct srte_policy *policy,
+                                          uint32_t preference);
+struct srte_segment_entry *
+srte_segment_entry_find(struct srte_segment_list *segment_list, uint32_t index);
+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);
+
+/* path_cli.c */
+void path_cli_init(void);
+
+#endif /* _FRR_PATHD_H_ */
diff --git a/pathd/subdir.am b/pathd/subdir.am
new file mode 100644 (file)
index 0000000..520a8c6
--- /dev/null
@@ -0,0 +1,74 @@
+#
+# pathd
+#
+
+if PATHD
+noinst_LIBRARIES += pathd/libpath.a
+sbin_PROGRAMS += pathd/pathd
+dist_examples_DATA += pathd/pathd.conf.sample
+vtysh_scan += $(top_srcdir)/pathd/path_cli.c
+vtysh_daemons += pathd
+# TODO add man page
+#man8 += $(MANBUILD)/pathd.8
+
+if HAVE_PATHD_PCEP
+vtysh_scan += $(top_srcdir)/pathd/path_pcep_cli.c
+module_LTLIBRARIES += pathd/pathd_pcep.la
+endif
+
+endif
+
+pathd_libpath_a_SOURCES = \
+       pathd/path_cli.c \
+       pathd/path_debug.c \
+       pathd/path_errors.c \
+       pathd/path_main.c \
+       pathd/path_memory.c \
+       pathd/path_nb.c \
+       pathd/path_nb_config.c \
+       pathd/path_nb_state.c \
+       pathd/path_zebra.c \
+       pathd/pathd.c \
+       # end
+
+clippy_scan += \
+       pathd/path_cli.c \
+       pathd/path_pcep_cli.c \
+       # end
+
+noinst_HEADERS += \
+       pathd/path_debug.h \
+       pathd/path_errors.h \
+       pathd/path_memory.h \
+       pathd/path_nb.h \
+       pathd/path_pcep.h \
+       pathd/path_pcep_cli.h \
+       pathd/path_pcep_controller.h \
+       pathd/path_pcep_debug.h \
+       pathd/path_pcep_lib.h \
+       pathd/path_pcep_memory.h \
+       pathd/path_pcep_config.h \
+       pathd/path_pcep_pcc.h \
+       pathd/path_zebra.h \
+       pathd/pathd.h \
+       # end
+
+pathd_pathd_SOURCES = pathd/path_main.c
+nodist_pathd_pathd_SOURCES = \
+       yang/frr-pathd.yang.c \
+       # end
+pathd_pathd_LDADD = pathd/libpath.a lib/libfrr.la -lm $(LIBCAP)
+
+pathd_pathd_pcep_la_SOURCES = \
+       pathd/path_pcep.c \
+       pathd/path_pcep_cli.c \
+       pathd/path_pcep_controller.c \
+       pathd/path_pcep_debug.c \
+       pathd/path_pcep_lib.c \
+       pathd/path_pcep_memory.c \
+       pathd/path_pcep_config.c \
+       pathd/path_pcep_pcc.c \
+       # end
+pathd_pathd_pcep_la_CFLAGS = $(WERROR)
+pathd_pathd_pcep_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+pathd_pathd_pcep_la_LIBADD = @PATHD_PCEP_LIBS@
index ce7780ed498f486a53dcd73e03a08921686aca80..f99971ab7b7a4dd63dbcc93ebf24e684d6acdf7b 100644 (file)
@@ -718,22 +718,72 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc,
                                     struct pbr_nht_individual *pnhi)
 {
        bool is_valid = pnhc->valid;
+       bool all_done = false;
 
-       if (!pnhi->nhr) /* It doesn't care about non-nexthop updates */
+       /*
+        * If we have an interface down event, let's note that
+        * it is happening and find all the nexthops that depend
+        * on that interface.  As that if we have an interface
+        * flapping fast enough it means that zebra might turn
+        * those nexthop tracking events into a no-update
+        * So let's search and do the right thing on the
+        * interface event.
+        */
+       if (!pnhi->nhr && pnhi->ifp) {
+               struct connected *connected;
+               struct listnode *node;
+               struct prefix p;
+
+               switch (pnhc->nexthop.type) {
+               case NEXTHOP_TYPE_BLACKHOLE:
+                       all_done = true;
+                       break;
+               case NEXTHOP_TYPE_IFINDEX:
+               case NEXTHOP_TYPE_IPV4_IFINDEX:
+               case NEXTHOP_TYPE_IPV6_IFINDEX:
+                       is_valid = if_is_up(pnhi->ifp);
+                       all_done = true;
+                       break;
+               case NEXTHOP_TYPE_IPV4:
+                       p.family = AF_INET;
+                       p.prefixlen = IPV4_MAX_BITLEN;
+                       p.u.prefix4 = pnhc->nexthop.gate.ipv4;
+                       break;
+               case NEXTHOP_TYPE_IPV6:
+                       p.family = AF_INET6;
+                       p.prefixlen = IPV6_MAX_BITLEN;
+                       memcpy(&p.u.prefix6, &pnhc->nexthop.gate.ipv6,
+                              sizeof(struct in6_addr));
+                       break;
+               }
+
+               /* Early exit in a couple of cases. */
+               if (all_done)
+                       goto done;
+
+               FOR_ALL_INTERFACES_ADDRESSES (pnhi->ifp, connected, node) {
+                       if (prefix_match(connected->address, &p)) {
+                               is_valid = if_is_up(pnhi->ifp);
+                               break;
+                       }
+               }
                goto done;
+       }
 
-       switch (pnhi->nhr->prefix.family) {
-       case AF_INET:
-               if (pnhc->nexthop.gate.ipv4.s_addr
-                   != pnhi->nhr->prefix.u.prefix4.s_addr)
-                       goto done; /* Unrelated change */
-               break;
-       case AF_INET6:
-               if (memcmp(&pnhc->nexthop.gate.ipv6,
-                          &pnhi->nhr->prefix.u.prefix6, 16)
-                   != 0)
-                       goto done; /* Unrelated change */
-               break;
+       if (pnhi->nhr) {
+               switch (pnhi->nhr->prefix.family) {
+               case AF_INET:
+                       if (pnhc->nexthop.gate.ipv4.s_addr
+                           != pnhi->nhr->prefix.u.prefix4.s_addr)
+                               goto done; /* Unrelated change */
+                       break;
+               case AF_INET6:
+                       if (memcmp(&pnhc->nexthop.gate.ipv6,
+                                  &pnhi->nhr->prefix.u.prefix6, 16)
+                           != 0)
+                               goto done; /* Unrelated change */
+                       break;
+               }
        }
 
        pnhi->nhr_matched = true;
@@ -983,7 +1033,6 @@ static void pbr_nht_nexthop_vrf_handle(struct hash_bucket *b, void *data)
        struct pbr_vrf *pbr_vrf = data;
        struct pbr_nht_individual pnhi = {};
 
-       zlog_debug("pnhgc iterating");
        hash_iterate(pnhgc->nhh, pbr_nht_clear_looked_at, NULL);
        memset(&pnhi, 0, sizeof(pnhi));
        pnhi.pbr_vrf = pbr_vrf;
@@ -1097,6 +1146,7 @@ static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b,
 {
        struct pbr_nexthop_group_cache *pnhgc = b->data;
        struct pbr_nht_individual pnhi = {};
+       struct nexthop_group nhg = {};
        bool old_valid;
 
        old_valid = pnhgc->valid;
@@ -1111,6 +1161,15 @@ static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b,
         */
        pnhgc->valid = pnhi.valid;
 
+       pbr_nexthop_group_cache_to_nexthop_group(&nhg, pnhgc);
+
+       if (pnhgc->valid)
+               pbr_nht_install_nexthop_group(pnhgc, nhg);
+       else
+               pbr_nht_uninstall_nexthop_group(pnhgc, nhg, 0);
+
+       nexthops_free(nhg.nexthop);
+
        if (old_valid != pnhgc->valid)
                pbr_map_check_nh_group_change(pnhgc->name);
 }
index 26163dcc56de3e5fdfb7d3f7c3058f9e2330978f..216834fe0c60c6b84ccdc044b6e3c52eb870eb18 100644 (file)
@@ -137,6 +137,11 @@ DEFPY(pbr_map_match_src, pbr_map_match_src_cmd,
 {
        struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
 
+       if (pbrms->dst && pbrms->family && prefix->family != pbrms->family) {
+               vty_out(vty, "Cannot mismatch families within match src/dst\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        pbrms->family = prefix->family;
 
        if (!no) {
@@ -165,6 +170,11 @@ DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd,
 {
        struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
 
+       if (pbrms->src && pbrms->family && prefix->family != pbrms->family) {
+               vty_out(vty, "Cannot mismatch families within match src/dst\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        pbrms->family = prefix->family;
 
        if (!no) {
index 82a2d2feb51f7ae739358bd168ea83a14b2d8add..222a10e7510582600d152ca8213f648f79453a3b 100644 (file)
@@ -476,8 +476,8 @@ void pbr_send_rnh(struct nexthop *nhop, bool reg)
                break;
        }
 
-       if (zclient_send_rnh(zclient, command, &p,
-                            false, nhop->vrf_id) < 0) {
+       if (zclient_send_rnh(zclient, command, &p, false, nhop->vrf_id)
+           == ZCLIENT_SEND_FAILURE) {
                zlog_warn("%s: Failure to send nexthop to zebra", __func__);
        }
 }
index 1acfece895a0aaeed020b01e19273355552facc5..e873af57598ccaa517e320b2ccb3987f1243f17d 100644 (file)
@@ -63,7 +63,7 @@ void pim_bsm_write_config(struct vty *vty, struct interface *ifp)
        }
 }
 
-static void pim_free_bsgrp_data(struct bsgrp_node *bsgrp_node)
+void pim_free_bsgrp_data(struct bsgrp_node *bsgrp_node)
 {
        if (bsgrp_node->bsrp_list)
                list_delete(&bsgrp_node->bsrp_list);
@@ -72,7 +72,7 @@ static void pim_free_bsgrp_data(struct bsgrp_node *bsgrp_node)
        XFREE(MTYPE_PIM_BSGRP_NODE, bsgrp_node);
 }
 
-static void pim_free_bsgrp_node(struct route_table *rt, struct prefix *grp)
+void pim_free_bsgrp_node(struct route_table *rt, struct prefix *grp)
 {
        struct route_node *rn;
 
@@ -222,7 +222,7 @@ static int pim_on_bs_timer(struct thread *t)
        return 0;
 }
 
-static void pim_bs_timer_stop(struct bsm_scope *scope)
+void pim_bs_timer_stop(struct bsm_scope *scope)
 {
        if (PIM_DEBUG_BSM)
                zlog_debug("%s : BS timer being stopped of sz: %d", __func__,
index 0758c94f1947400c687006da7d25f15a6ee4abe6..2829c1e05a46d06e8fec78525f41bfd22b1229b5 100644 (file)
@@ -195,4 +195,7 @@ int  pim_bsm_process(struct interface *ifp,
 bool pim_bsm_new_nbr_fwd(struct pim_neighbor *neigh, struct interface *ifp);
 struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope,
                                          struct prefix *grp);
+void pim_bs_timer_stop(struct bsm_scope *scope);
+void pim_free_bsgrp_data(struct bsgrp_node *bsgrp_node);
+void pim_free_bsgrp_node(struct route_table *rt, struct prefix *grp);
 #endif
index 2a7ff4e7f8ecef5c6d46ac5c8592bb66bb24a019..ff85151839444fb7a2c8334eba24eb9bea7d56ed 100644 (file)
@@ -64,6 +64,9 @@
 #include "pim_mlag.h"
 #include "bfd.h"
 #include "pim_bsm.h"
+#include "lib/northbound_cli.h"
+#include "pim_errors.h"
+#include "pim_nb.h"
 
 #ifndef VTYSH_EXTRACT_PL
 #include "pimd/pim_cmd_clippy.c"
@@ -101,94 +104,6 @@ static struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[],
        return vrf;
 }
 
-static void pim_if_membership_clear(struct interface *ifp)
-{
-       struct pim_interface *pim_ifp;
-
-       pim_ifp = ifp->info;
-       zassert(pim_ifp);
-
-       if (PIM_IF_TEST_PIM(pim_ifp->options)
-           && PIM_IF_TEST_IGMP(pim_ifp->options)) {
-               return;
-       }
-
-       pim_ifchannel_membership_clear(ifp);
-}
-
-/*
-  When PIM is disabled on interface, IGMPv3 local membership
-  information is not injected into PIM interface state.
-
-  The function pim_if_membership_refresh() fetches all IGMPv3 local
-  membership information into PIM. It is intented to be called
-  whenever PIM is enabled on the interface in order to collect missed
-  local membership information.
- */
-static void pim_if_membership_refresh(struct interface *ifp)
-{
-       struct pim_interface *pim_ifp;
-       struct listnode *sock_node;
-       struct igmp_sock *igmp;
-
-       pim_ifp = ifp->info;
-       zassert(pim_ifp);
-
-       if (!PIM_IF_TEST_PIM(pim_ifp->options))
-               return;
-       if (!PIM_IF_TEST_IGMP(pim_ifp->options))
-               return;
-
-       /*
-         First clear off membership from all PIM (S,G) entries on the
-         interface
-       */
-
-       pim_ifchannel_membership_clear(ifp);
-
-       /*
-         Then restore PIM (S,G) membership from all IGMPv3 (S,G) entries on
-         the interface
-       */
-
-       /* scan igmp sockets */
-       for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
-               struct listnode *grpnode;
-               struct igmp_group *grp;
-
-               /* scan igmp groups */
-               for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode,
-                                         grp)) {
-                       struct listnode *srcnode;
-                       struct igmp_source *src;
-
-                       /* scan group sources */
-                       for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
-                                                 srcnode, src)) {
-
-                               if (IGMP_SOURCE_TEST_FORWARDING(
-                                           src->source_flags)) {
-                                       struct prefix_sg sg;
-
-                                       memset(&sg, 0,
-                                              sizeof(struct prefix_sg));
-                                       sg.src = src->source_addr;
-                                       sg.grp = grp->group_addr;
-                                       pim_ifchannel_local_membership_add(ifp,
-                                               &sg, false /*is_vxlan*/);
-                               }
-
-                       } /* scan group sources */
-               }        /* scan igmp groups */
-       }                 /* scan igmp sockets */
-
-       /*
-         Finally delete every PIM (S,G) entry lacking all state info
-        */
-
-       pim_ifchannel_delete_on_noinfo(ifp);
-}
-
 static void pim_show_assert_helper(struct vty *vty,
                                   struct pim_interface *pim_ifp,
                                   struct pim_ifchannel *ch, time_t now)
@@ -261,7 +176,7 @@ static void pim_show_assert_internal_helper(struct vty *vty,
                PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags) ? "yes" : "no",
                pim_macro_ch_could_assert_eval(ch) ? "yes" : "no",
                PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags) ? "yes"
-                                                                   : "no",
+               : "no",
                pim_macro_assert_tracking_desired_eval(ch) ? "yes" : "no");
 }
 
@@ -455,8 +370,8 @@ static void pim_show_membership_helper(struct vty *vty,
        json_object_string_add(json_row, "group", ch_grp_str);
        json_object_string_add(json_row, "localMembership",
                               ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO
-                                      ? "NOINFO"
-                                      : "INCLUDE");
+                              ? "NOINFO"
+                              : "INCLUDE");
        json_object_object_add(json_iface, ch_grp_str, json_row);
 }
 static void pim_show_membership(struct pim_instance *pim, struct vty *vty,
@@ -483,7 +398,7 @@ static void pim_show_membership(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
        } else {
                vty_out(vty,
                        "Interface         Address          Source           Group            Membership\n");
@@ -642,14 +557,14 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty,
                                        "%-16s  %5s  %15s  %d  %7s  %11s  %8s\n",
                                        ifp->name,
                                        if_is_up(ifp)
-                                               ? (igmp->mtrace_only ? "mtrc"
-                                                                    : "up")
-                                               : "down",
+                                       ? (igmp->mtrace_only ? "mtrc"
+                                          : "up")
+                                       : "down",
                                        inet_ntop(AF_INET, &igmp->ifaddr,
                                                  buf, sizeof(buf)),
                                        pim_ifp->igmp_version,
                                        igmp->t_igmp_query_timer ? "local"
-                                                                : "other",
+                                       : "other",
                                        query_hhmmss, uptime);
                        }
                }
@@ -657,7 +572,7 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -738,7 +653,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
                                * 100;
 
                        qri_msec = pim_ifp->igmp_query_max_response_time_dsec
-                                  * 100;
+                               * 100;
                        if (pim_ifp->pim_sock_fd >= 0)
                                mloop = pim_socket_mcastloop_get(
                                        pim_ifp->pim_sock_fd);
@@ -753,8 +668,8 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
                                                       uptime);
                                json_object_string_add(json_row, "querier",
                                                       igmp->t_igmp_query_timer
-                                                              ? "local"
-                                                              : "other");
+                                                      ? "local"
+                                                      : "other");
                                json_object_int_add(json_row, "queryStartCount",
                                                    igmp->startup_query_count);
                                json_object_string_add(json_row,
@@ -807,10 +722,10 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
                        } else {
                                vty_out(vty, "Interface : %s\n", ifp->name);
                                vty_out(vty, "State     : %s\n",
-                                       if_is_up(ifp)
-                                               ? (igmp->mtrace_only ? "mtrace"
-                                                                    : "up")
-                                               : "down");
+                                       if_is_up(ifp) ? (igmp->mtrace_only ?
+                                                        "mtrace"
+                                                        : "up")
+                                       : "down");
                                vty_out(vty, "Address   : %pI4\n",
                                        &pim_ifp->primary_address);
                                vty_out(vty, "Uptime    : %s\n", uptime);
@@ -823,7 +738,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
                                vty_out(vty, "-------\n");
                                vty_out(vty, "Querier     : %s\n",
                                        igmp->t_igmp_query_timer ? "local"
-                                                                : "other");
+                                       : "other");
                                vty_out(vty, "Start Count : %d\n",
                                        igmp->startup_query_count);
                                vty_out(vty, "Query Timer : %s\n",
@@ -872,7 +787,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else {
                if (!found_ifname)
@@ -1245,7 +1160,7 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
 
                                if (strcmp(ifp->name,
                                           up->rpf.source_nexthop
-                                                  .interface->name)
+                                          .interface->name)
                                    != 0)
                                        continue;
 
@@ -1327,7 +1242,7 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else {
                if (!found_ifname)
@@ -1386,7 +1301,7 @@ static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty,
                json_object_object_add(json, ifname ? ifname : "global",
                                       json_row);
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else {
                vty_out(vty, "IGMP RX statistics\n");
@@ -1459,7 +1374,7 @@ static void pim_show_interfaces(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
        } else {
                vty_out(vty,
                        "Interface         State          Address  PIM Nbrs           PIM DR  FHR IfChannels\n");
@@ -1561,11 +1476,11 @@ static void pim_show_interface_traffic(struct pim_instance *pim,
                        json_object_int_add(json_row, "assertRx",
                                            pim_ifp->pim_ifstat_assert_recv);
                        json_object_int_add(json_row, "assertTx",
-                                       pim_ifp->pim_ifstat_assert_send);
+                                           pim_ifp->pim_ifstat_assert_send);
                        json_object_int_add(json_row, "bsmRx",
-                                       pim_ifp->pim_ifstat_bsm_rx);
+                                           pim_ifp->pim_ifstat_bsm_rx);
                        json_object_int_add(json_row, "bsmTx",
-                                       pim_ifp->pim_ifstat_bsm_tx);
+                                           pim_ifp->pim_ifstat_bsm_tx);
                        json_object_object_add(json, ifp->name, json_row);
                } else {
                        vty_out(vty,
@@ -1588,7 +1503,7 @@ static void pim_show_interface_traffic(struct pim_instance *pim,
        }
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -1681,7 +1596,7 @@ static void pim_show_interface_traffic_single(struct pim_instance *pim,
        }
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else {
                if (!found_ifname)
@@ -1794,7 +1709,7 @@ static void pim_show_join(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -1997,7 +1912,7 @@ static void pim_show_neighbors_single(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else {
                {
@@ -2041,8 +1956,8 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                first_oif = 1;
 
                if ((c_oil->up &&
-                       PIM_UPSTREAM_FLAG_TEST_USE_RPT(c_oil->up->flags)) ||
-                       c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
+                    PIM_UPSTREAM_FLAG_TEST_USE_RPT(c_oil->up->flags)) ||
+                   c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
                        isRpt = true;
                else
                        isRpt = false;
@@ -2102,10 +2017,10 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                                                    c_oil->installed);
                                if (isRpt)
                                        json_object_boolean_true_add(
-                                                       json_source, "isRpt");
+                                               json_source, "isRpt");
                                else
                                        json_object_boolean_false_add(
-                                                       json_source, "isRpt");
+                                               json_source, "isRpt");
                                json_object_int_add(json_source, "RefCount",
                                                    c_oil->oil_ref_count);
                                json_object_int_add(json_source, "OilListSize",
@@ -2125,8 +2040,8 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                        }
                } else {
                        vty_out(vty, "%-6d %-15s  %-15s  %-3s  %-16s  ",
-                                       c_oil->installed, src_str, grp_str,
-                                       isRpt ? "y" : "n", in_ifname);
+                               c_oil->installed, src_str, grp_str,
+                               isRpt ? "y" : "n", in_ifname);
                }
 
                for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
@@ -2173,47 +2088,47 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                                                out_ifname,
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_IGMP)
-                                                       ? 'I'
-                                                       : ' ',
+                                               ? 'I'
+                                               : ' ',
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_PIM)
-                                                       ? 'J'
-                                                       : ' ',
+                                               ? 'J'
+                                               : ' ',
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_VXLAN)
-                                                       ? 'V'
-                                                       : ' ',
+                                               ? 'V'
+                                               : ' ',
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_STAR)
-                                                       ? '*'
-                                                       : ' ',
+                                               ? '*'
+                                               : ' ',
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_MUTE)
-                                                       ? 'M'
-                                                       : ' ');
+                                               ? 'M'
+                                               : ' ');
                                } else
                                        vty_out(vty, ", %s(%c%c%c%c%c)",
                                                out_ifname,
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_IGMP)
-                                                       ? 'I'
-                                                       : ' ',
+                                               ? 'I'
+                                               : ' ',
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_PIM)
-                                                       ? 'J'
-                                                       : ' ',
+                                               ? 'J'
+                                               : ' ',
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_VXLAN)
-                                                       ? 'V'
-                                                       : ' ',
+                                               ? 'V'
+                                               : ' ',
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_PROTO_STAR)
-                                                       ? '*'
-                                                       : ' ',
+                                               ? '*'
+                                               : ' ',
                                                (c_oil->oif_flags[oif_vif_index]
                                                 & PIM_OIF_FLAG_MUTE)
-                                                       ? 'M'
-                                                       : ' ');
+                                               ? 'M'
+                                               : ' ');
                        }
                }
 
@@ -2224,7 +2139,7 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else {
                vty_out(vty, "\n");
@@ -2308,7 +2223,7 @@ static void pim_show_neighbors(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -2546,8 +2461,8 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
                        json_row = json_object_new_object();
                        json_object_pim_upstream_add(json_row, up);
                        json_object_string_add(
-                           json_row, "inboundInterface",
-                           up->rpf.source_nexthop.interface
+                               json_row, "inboundInterface",
+                               up->rpf.source_nexthop.interface
                                ? up->rpf.source_nexthop.interface->name
                                : "Unknown");
 
@@ -2600,8 +2515,8 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
                        vty_out(vty,
                                "%-16s%-15s %-15s %-11s %-8s %-9s %-9s %-9s %6d\n",
                                up->rpf.source_nexthop.interface
-                                   ? up->rpf.source_nexthop.interface->name
-                                   : "Unknown",
+                               ? up->rpf.source_nexthop.interface->name
+                               : "Unknown",
                                src_str, grp_str, state_str, uptime, join_timer,
                                rs_timer, ka_timer, up->ref_count);
                }
@@ -2609,16 +2524,16 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
 
 static void pim_show_channel_helper(struct pim_instance *pim,
-                                        struct vty *vty,
-                                        struct pim_interface *pim_ifp,
-                                        struct pim_ifchannel *ch,
-                                        json_object *json, bool uj)
+                                   struct vty *vty,
+                                   struct pim_interface *pim_ifp,
+                                   struct pim_ifchannel *ch,
+                                   json_object *json, bool uj)
 {
        struct pim_upstream *up = ch->upstream;
        json_object *json_group = NULL;
@@ -2666,15 +2581,15 @@ static void pim_show_channel_helper(struct pim_instance *pim,
                        pim_macro_chisin_joins(ch) ? "yes" : "no",
                        pim_macro_chisin_pim_include(ch) ? "yes" : "no",
                        PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags)
-                               ? "yes"
-                               : "no",
+                       ? "yes"
+                       : "no",
                        pim_upstream_evaluate_join_desired(pim, up) ? "yes"
-                                                                   : "no");
+                       : "no");
        }
 }
 
 static void pim_show_channel(struct pim_instance *pim, struct vty *vty,
-                                 bool uj)
+                            bool uj)
 {
        struct pim_interface *pim_ifp;
        struct pim_ifchannel *ch;
@@ -2698,13 +2613,13 @@ static void pim_show_channel(struct pim_instance *pim, struct vty *vty,
                RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
                        /* scan all interfaces */
                        pim_show_channel_helper(pim, vty, pim_ifp, ch,
-                                                    json, uj);
+                                               json, uj);
                }
        }
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -2745,7 +2660,7 @@ static void pim_show_join_desired_helper(struct pim_instance *pim,
                vty_out(vty, "%-15s %-15s %-6s\n",
                        src_str, grp_str,
                        pim_upstream_evaluate_join_desired(pim, up) ? "yes"
-                                                                   : "no");
+                       : "no");
        }
 }
 
@@ -2765,12 +2680,12 @@ static void pim_show_join_desired(struct pim_instance *pim, struct vty *vty,
        frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                /* scan all interfaces */
                pim_show_join_desired_helper(pim, vty, up,
-                               json, uj);
+                                            json, uj);
        }
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -2838,7 +2753,7 @@ static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -2981,7 +2896,7 @@ static void pim_show_rpf(struct pim_instance *pim, struct vty *vty, bool uj)
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -3183,7 +3098,7 @@ static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -3333,7 +3248,7 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -3408,7 +3323,7 @@ static void pim_show_statistics(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -3507,9 +3422,9 @@ static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj)
                                                json_groups =
                                                        json_object_new_array();
                                                json_object_object_add(
-                                                               json_iface,
-                                                               "groups",
-                                                               json_groups);
+                                                       json_iface,
+                                                       "groups",
+                                                       json_groups);
                                        }
 
                                        json_group = json_object_new_object();
@@ -3524,20 +3439,20 @@ static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj)
                                                json_object_string_add(
                                                        json_group, "mode",
                                                        grp->group_filtermode_isexcl
-                                                               ? "EXCLUDE"
-                                                               : "INCLUDE");
+                                                       ? "EXCLUDE"
+                                                       : "INCLUDE");
 
                                        json_object_string_add(json_group,
                                                               "timer", hhmmss);
                                        json_object_int_add(
                                                json_group, "sourcesCount",
                                                grp->group_source_list
-                                                       ? listcount(
-                                                                 grp->group_source_list)
-                                                       : 0);
+                                               ? listcount(
+                                                       grp->group_source_list)
+                                               : 0);
                                        json_object_int_add(
-                                                       json_group, "version",
-                                                       grp->igmp_version);
+                                               json_group, "version",
+                                               grp->igmp_version);
                                        json_object_string_add(
                                                json_group, "uptime", uptime);
                                        json_object_array_add(json_groups,
@@ -3548,15 +3463,15 @@ static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj)
                                                ifp->name, ifaddr_str,
                                                group_str,
                                                grp->igmp_version == 3
-                                                       ? (grp->group_filtermode_isexcl
-                                                                  ? "EXCL"
-                                                                  : "INCL")
-                                                       : "----",
+                                               ? (grp->group_filtermode_isexcl
+                                                  ? "EXCL"
+                                                  : "INCL")
+                                               : "----",
                                                hhmmss,
                                                grp->group_source_list
-                                                       ? listcount(
-                                                                 grp->group_source_list)
-                                                       : 0,
+                                               ? listcount(
+                                                       grp->group_source_list)
+                                               : 0,
                                                grp->igmp_version, uptime);
                                }
                        } /* scan igmp groups */
@@ -3565,7 +3480,7 @@ static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj)
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -3700,8 +3615,8 @@ static void igmp_show_sources(struct pim_instance *pim, struct vty *vty)
                                                group_str, source_str, mmss,
                                                IGMP_SOURCE_TEST_FORWARDING(
                                                        src->source_flags)
-                                                       ? "Y"
-                                                       : "N",
+                                               ? "Y"
+                                               : "N",
                                                uptime);
 
                                } /* scan group sources */
@@ -3839,7 +3754,7 @@ static void pim_show_bsr(struct pim_instance *pim,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -3872,12 +3787,12 @@ static void clear_interfaces(struct pim_instance *pim)
        clear_pim_interfaces(pim);
 }
 
-#define PIM_GET_PIM_INTERFACE(pim_ifp, ifp)                                     \
-       pim_ifp = ifp->info;                                                    \
-       if (!pim_ifp) {                                                         \
-               vty_out(vty,                                                    \
+#define PIM_GET_PIM_INTERFACE(pim_ifp, ifp)                            \
+       pim_ifp = ifp->info;                                            \
+       if (!pim_ifp) {                                                 \
+               vty_out(vty,                                            \
                        "%% Enable PIM and/or IGMP on this interface first\n"); \
-               return CMD_WARNING_CONFIG_FAILED;                               \
+               return CMD_WARNING_CONFIG_FAILED;                       \
        }
 
 DEFUN (clear_ip_interfaces,
@@ -3963,7 +3878,7 @@ static void clear_mroute(struct pim_instance *pim)
                /* clean up all igmp groups */
                /* scan igmp sockets */
                for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
-                                       igmp)) {
+                                         igmp)) {
 
                        struct igmp_group *grp;
 
@@ -3979,9 +3894,9 @@ static void clear_mroute(struct pim_instance *pim)
        }
 
        /* clean up all upstreams*/
-       while ((up = rb_pim_upstream_first(&pim->upstream_head))) {
+       while ((up = rb_pim_upstream_first(&pim->upstream_head)))
                pim_upstream_del(pim, up, __func__);
-       }
+
 }
 
 DEFUN (clear_ip_mroute,
@@ -4086,6 +4001,152 @@ DEFUN (clear_ip_pim_oil,
        return CMD_SUCCESS;
 }
 
+static void clear_pim_bsr_db(struct pim_instance *pim)
+{
+       struct route_node *rn;
+       struct route_node *rpnode;
+       struct bsgrp_node *bsgrp;
+       struct prefix nht_p;
+       struct prefix g_all;
+       struct rp_info *rp_all;
+       struct pim_upstream *up;
+       struct rp_info *rp_info;
+       bool is_bsr_tracking = true;
+
+       /* Remove next hop tracking for the bsr */
+       nht_p.family = AF_INET;
+       nht_p.prefixlen = IPV4_MAX_BITLEN;
+       nht_p.u.prefix4 = pim->global_scope.current_bsr;
+       if (PIM_DEBUG_BSM) {
+               zlog_debug("%s: Deregister BSR addr %pFX with Zebra NHT",
+                          __func__, &nht_p);
+       }
+       pim_delete_tracked_nexthop(pim, &nht_p, NULL, NULL, is_bsr_tracking);
+
+       /* Reset scope zone data */
+       pim->global_scope.accept_nofwd_bsm = false;
+       pim->global_scope.state = ACCEPT_ANY;
+       pim->global_scope.current_bsr.s_addr = INADDR_ANY;
+       pim->global_scope.current_bsr_prio = 0;
+       pim->global_scope.current_bsr_first_ts = 0;
+       pim->global_scope.current_bsr_last_ts = 0;
+       pim->global_scope.bsm_frag_tag = 0;
+       list_delete_all_node(pim->global_scope.bsm_list);
+
+       pim_bs_timer_stop(&pim->global_scope);
+
+       for (rn = route_top(pim->global_scope.bsrp_table); rn;
+            rn = route_next(rn)) {
+               bsgrp = rn->info;
+               if (!bsgrp)
+                       continue;
+
+               rpnode = route_node_lookup(pim->rp_table, &bsgrp->group);
+
+               if (!rpnode) {
+                       pim_free_bsgrp_node(bsgrp->scope->bsrp_table,
+                                           &bsgrp->group);
+                       pim_free_bsgrp_data(bsgrp);
+                       continue;
+               }
+
+               rp_info = (struct rp_info *)rpnode->info;
+
+               if ((!rp_info) || (rp_info->rp_src != RP_SRC_BSR)) {
+                       pim_free_bsgrp_node(bsgrp->scope->bsrp_table,
+                                           &bsgrp->group);
+                       pim_free_bsgrp_data(bsgrp);
+                       continue;
+               }
+
+               /* Deregister addr with Zebra NHT */
+               nht_p.family = AF_INET;
+               nht_p.prefixlen = IPV4_MAX_BITLEN;
+               nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+
+               if (PIM_DEBUG_PIM_NHT_RP) {
+                       zlog_debug("%s: Deregister RP addr %pFX with Zebra ",
+                                  __func__, &nht_p);
+               }
+
+               pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info, false);
+
+               if (!str2prefix("224.0.0.0/4", &g_all))
+                       return;
+
+               rp_all = pim_rp_find_match_group(pim, &g_all);
+
+               if (rp_all == rp_info) {
+                       rp_all->rp.rpf_addr.family = AF_INET;
+                       rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
+                       rp_all->i_am_rp = 0;
+               } else {
+                       /* Delete the rp_info from rp-list */
+                       listnode_delete(pim->rp_list, rp_info);
+
+                       /* Delete the rp node from rp_table */
+                       rpnode->info = NULL;
+                       route_unlock_node(rpnode);
+                       route_unlock_node(rpnode);
+               }
+
+               XFREE(MTYPE_PIM_RP, rp_info);
+
+               pim_free_bsgrp_node(bsgrp->scope->bsrp_table, &bsgrp->group);
+               pim_free_bsgrp_data(bsgrp);
+       }
+       pim_rp_refresh_group_to_rp_mapping(pim);
+
+
+       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
+               /* Find the upstream (*, G) whose upstream address is same as
+                * the RP
+                */
+               if (up->sg.src.s_addr != INADDR_ANY)
+                       continue;
+
+               struct prefix grp;
+               struct rp_info *trp_info;
+
+               grp.family = AF_INET;
+               grp.prefixlen = IPV4_MAX_BITLEN;
+               grp.u.prefix4 = up->sg.grp;
+
+               trp_info = pim_rp_find_match_group(pim, &grp);
+
+               /* RP not found for the group grp */
+               if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) {
+                       pim_upstream_rpf_clear(pim, up);
+                       pim_rp_set_upstream_addr(pim, &up->upstream_addr,
+                                                up->sg.src, up->sg.grp);
+               } else {
+                       /* RP found for the group grp */
+                       pim_upstream_update(pim, up);
+               }
+       }
+}
+
+
+DEFUN (clear_ip_pim_bsr_db,
+       clear_ip_pim_bsr_db_cmd,
+       "clear ip pim [vrf NAME] bsr-data",
+       CLEAR_STR
+       IP_STR
+       CLEAR_IP_PIM_STR
+       VRF_CMD_HELP_STR
+       "Reset pim bsr data\n")
+{
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       clear_pim_bsr_db(vrf->info);
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (show_ip_igmp_interface,
        show_ip_igmp_interface_cmd,
        "show ip igmp [vrf NAME] interface [detail|WORD] [json]",
@@ -4374,83 +4435,83 @@ DEFUN (show_ip_pim_mlag_summary,
                if (router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP)
                        json_object_boolean_true_add(json, "mlagPeerZebraUp");
                json_object_string_add(json, "mlagRole",
-                               mlag_role2str(router->mlag_role,
-                                       role_buf, sizeof(role_buf)));
+                                      mlag_role2str(router->mlag_role,
+                                                    role_buf, sizeof(role_buf)));
                inet_ntop(AF_INET, &router->local_vtep_ip,
-                               addr_buf, INET_ADDRSTRLEN);
+                         addr_buf, INET_ADDRSTRLEN);
                json_object_string_add(json, "localVtepIp", addr_buf);
                inet_ntop(AF_INET, &router->anycast_vtep_ip,
-                               addr_buf, INET_ADDRSTRLEN);
+                         addr_buf, INET_ADDRSTRLEN);
                json_object_string_add(json, "anycastVtepIp", addr_buf);
                json_object_string_add(json, "peerlinkRif",
-                               router->peerlink_rif);
+                                      router->peerlink_rif);
 
                json_stat = json_object_new_object();
                json_object_int_add(json_stat, "mlagConnFlaps",
-                               router->mlag_stats.mlagd_session_downs);
+                                   router->mlag_stats.mlagd_session_downs);
                json_object_int_add(json_stat, "mlagPeerConnFlaps",
-                               router->mlag_stats.peer_session_downs);
+                                   router->mlag_stats.peer_session_downs);
                json_object_int_add(json_stat, "mlagPeerZebraFlaps",
-                               router->mlag_stats.peer_zebra_downs);
+                                   router->mlag_stats.peer_zebra_downs);
                json_object_int_add(json_stat, "mrouteAddRx",
-                               router->mlag_stats.msg.mroute_add_rx);
+                                   router->mlag_stats.msg.mroute_add_rx);
                json_object_int_add(json_stat, "mrouteAddTx",
-                               router->mlag_stats.msg.mroute_add_tx);
+                                   router->mlag_stats.msg.mroute_add_tx);
                json_object_int_add(json_stat, "mrouteDelRx",
-                               router->mlag_stats.msg.mroute_del_rx);
+                                   router->mlag_stats.msg.mroute_del_rx);
                json_object_int_add(json_stat, "mrouteDelTx",
-                               router->mlag_stats.msg.mroute_del_tx);
+                                   router->mlag_stats.msg.mroute_del_tx);
                json_object_int_add(json_stat, "mlagStatusUpdates",
-                               router->mlag_stats.msg.mlag_status_updates);
+                                   router->mlag_stats.msg.mlag_status_updates);
                json_object_int_add(json_stat, "peerZebraStatusUpdates",
-                       router->mlag_stats.msg.peer_zebra_status_updates);
+                                   router->mlag_stats.msg.peer_zebra_status_updates);
                json_object_int_add(json_stat, "pimStatusUpdates",
-                               router->mlag_stats.msg.pim_status_updates);
+                                   router->mlag_stats.msg.pim_status_updates);
                json_object_int_add(json_stat, "vxlanUpdates",
-                               router->mlag_stats.msg.vxlan_updates);
+                                   router->mlag_stats.msg.vxlan_updates);
                json_object_object_add(json, "connStats", json_stat);
 
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                       json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
                return CMD_SUCCESS;
        }
 
        vty_out(vty, "MLAG daemon connection: %s\n",
                (router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)
-                       ? "up" : "down");
+               ? "up" : "down");
        vty_out(vty, "MLAG peer state: %s\n",
                (router->mlag_flags & PIM_MLAGF_PEER_CONN_UP)
-                       ? "up" : "down");
+               ? "up" : "down");
        vty_out(vty, "Zebra peer state: %s\n",
                (router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP)
-                       ? "up" : "down");
+               ? "up" : "down");
        vty_out(vty, "MLAG role: %s\n",
                mlag_role2str(router->mlag_role, role_buf, sizeof(role_buf)));
        inet_ntop(AF_INET, &router->local_vtep_ip,
-                       addr_buf, INET_ADDRSTRLEN);
+                 addr_buf, INET_ADDRSTRLEN);
        vty_out(vty, "Local VTEP IP: %s\n", addr_buf);
        inet_ntop(AF_INET, &router->anycast_vtep_ip,
-                       addr_buf, INET_ADDRSTRLEN);
+                 addr_buf, INET_ADDRSTRLEN);
        vty_out(vty, "Anycast VTEP IP: %s\n", addr_buf);
        vty_out(vty, "Peerlink: %s\n", router->peerlink_rif);
        vty_out(vty, "Session flaps: mlagd: %d mlag-peer: %d zebra-peer: %d\n",
-                       router->mlag_stats.mlagd_session_downs,
-                       router->mlag_stats.peer_session_downs,
-                       router->mlag_stats.peer_zebra_downs);
+               router->mlag_stats.mlagd_session_downs,
+               router->mlag_stats.peer_session_downs,
+               router->mlag_stats.peer_zebra_downs);
        vty_out(vty, "Message Statistics:\n");
        vty_out(vty, "  mroute adds: rx: %d, tx: %d\n",
-                       router->mlag_stats.msg.mroute_add_rx,
-                       router->mlag_stats.msg.mroute_add_tx);
+               router->mlag_stats.msg.mroute_add_rx,
+               router->mlag_stats.msg.mroute_add_tx);
        vty_out(vty, "  mroute dels: rx: %d, tx: %d\n",
-                       router->mlag_stats.msg.mroute_del_rx,
-                       router->mlag_stats.msg.mroute_del_tx);
+               router->mlag_stats.msg.mroute_del_rx,
+               router->mlag_stats.msg.mroute_del_tx);
        vty_out(vty, "  peer zebra status updates: %d\n",
-                       router->mlag_stats.msg.peer_zebra_status_updates);
+               router->mlag_stats.msg.peer_zebra_status_updates);
        vty_out(vty, "  PIM status updates: %d\n",
-                       router->mlag_stats.msg.pim_status_updates);
+               router->mlag_stats.msg.pim_status_updates);
        vty_out(vty, "  VxLAN updates: %d\n",
-                       router->mlag_stats.msg.vxlan_updates);
+               router->mlag_stats.msg.vxlan_updates);
 
        return CMD_SUCCESS;
 }
@@ -4645,8 +4706,8 @@ DEFPY (show_ip_pim_join,
                return CMD_WARNING;
        }
 
-       if (s_or_g.s_addr != 0) {
-               if (g.s_addr != 0) {
+       if (s_or_g.s_addr != INADDR_ANY) {
+               if (g.s_addr != INADDR_ANY) {
                        sg.src = s_or_g;
                        sg.grp = g;
                } else
@@ -4692,10 +4753,10 @@ DEFUN (show_ip_pim_join_vrf_all,
 }
 
 static void pim_show_jp_agg_helper(struct vty *vty,
-               struct interface *ifp,
-               struct pim_neighbor *neigh,
-               struct pim_upstream *up,
-               int is_join)
+                                  struct interface *ifp,
+                                  struct pim_neighbor *neigh,
+                                  struct pim_upstream *up,
+                                  int is_join)
 {
        char src_str[INET_ADDRSTRLEN];
        char grp_str[INET_ADDRSTRLEN];
@@ -4703,12 +4764,12 @@ static void pim_show_jp_agg_helper(struct vty *vty,
 
        pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
        pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
-                       /* pius->address.s_addr */
+       /* pius->address.s_addr */
        pim_inet4_dump("<rpf?>", neigh->source_addr, rpf_str, sizeof(rpf_str));
 
        vty_out(vty, "%-16s %-15s %-15s %-15s %5s\n",
-                       ifp->name, rpf_str, src_str,
-                       grp_str, is_join?"J":"P");
+               ifp->name, rpf_str, src_str,
+               grp_str, is_join?"J":"P");
 }
 
 static void pim_show_jp_agg_list(struct pim_instance *pim, struct vty *vty)
@@ -4723,7 +4784,7 @@ static void pim_show_jp_agg_list(struct pim_instance *pim, struct vty *vty)
        struct pim_jp_sources *js;
 
        vty_out(vty,
-                       "Interface        RPF Nbr         Source          Group           State\n");
+               "Interface        RPF Nbr         Source          Group           State\n");
 
        FOR_ALL_INTERFACES (pim->vrf, ifp) {
                pim_ifp = ifp->info;
@@ -4731,14 +4792,14 @@ static void pim_show_jp_agg_list(struct pim_instance *pim, struct vty *vty)
                        continue;
 
                for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list,
-                                       n_node, neigh)) {
+                                         n_node, neigh)) {
                        for (ALL_LIST_ELEMENTS_RO(neigh->upstream_jp_agg,
-                                               jag_node, jag)) {
+                                                 jag_node, jag)) {
                                for (ALL_LIST_ELEMENTS_RO(jag->sources,
-                                                       js_node, js)) {
+                                                         js_node, js)) {
                                        pim_show_jp_agg_helper(vty,
-                                                       ifp, neigh, js->up,
-                                                       js->is_join);
+                                                              ifp, neigh, js->up,
+                                                              js->is_join);
                                }
                        }
                }
@@ -4798,8 +4859,10 @@ DEFUN (show_ip_pim_local_membership,
 }
 
 static void pim_show_mlag_up_entry_detail(struct vrf *vrf,
-               struct vty *vty, struct pim_upstream *up,
-               char *src_str, char *grp_str, json_object *json)
+                                         struct vty *vty,
+                                         struct pim_upstream *up,
+                                         char *src_str, char *grp_str,
+                                         json_object *json)
 {
        if (json) {
                json_object *json_row = NULL;
@@ -4811,7 +4874,7 @@ static void pim_show_mlag_up_entry_detail(struct vrf *vrf,
                if (!json_group) {
                        json_group = json_object_new_object();
                        json_object_object_add(json, grp_str,
-                                       json_group);
+                                              json_group);
                }
 
                json_row = json_object_new_object();
@@ -4821,19 +4884,19 @@ static void pim_show_mlag_up_entry_detail(struct vrf *vrf,
                own_list = json_object_new_array();
                if (pim_up_mlag_is_local(up))
                        json_object_array_add(own_list,
-                                       json_object_new_string("local"));
+                                             json_object_new_string("local"));
                if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER))
                        json_object_array_add(own_list,
-                                       json_object_new_string("peer"));
+                                             json_object_new_string("peer"));
                if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
                        json_object_array_add(
                                own_list, json_object_new_string("Interface"));
                json_object_object_add(json_row, "owners", own_list);
 
                json_object_int_add(json_row, "localCost",
-                               pim_up_mlag_local_cost(up));
+                                   pim_up_mlag_local_cost(up));
                json_object_int_add(json_row, "peerCost",
-                               pim_up_mlag_peer_cost(up));
+                                   pim_up_mlag_peer_cost(up));
                if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags))
                        json_object_boolean_false_add(json_row, "df");
                else
@@ -4851,18 +4914,18 @@ static void pim_show_mlag_up_entry_detail(struct vrf *vrf,
                        strlcat(own_str, "I", sizeof(own_str));
                /* XXX - fixup, print paragraph output */
                vty_out(vty,
-                               "%-15s %-15s %-6s %-11u %-10d %2s\n",
-                               src_str, grp_str, own_str,
-                               pim_up_mlag_local_cost(up),
-                               pim_up_mlag_peer_cost(up),
-                               PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
-                               ? "n" : "y");
+                       "%-15s %-15s %-6s %-11u %-10d %2s\n",
+                       src_str, grp_str, own_str,
+                       pim_up_mlag_local_cost(up),
+                       pim_up_mlag_peer_cost(up),
+                       PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
+                       ? "n" : "y");
        }
 }
 
 static void pim_show_mlag_up_detail(struct vrf *vrf,
-               struct vty *vty, const char *src_or_group,
-               const char *group, bool uj)
+                                   struct vty *vty, const char *src_or_group,
+                                   const char *group, bool uj)
 {
        char src_str[INET_ADDRSTRLEN];
        char grp_str[INET_ADDRSTRLEN];
@@ -4938,7 +5001,7 @@ static void pim_show_mlag_up_vrf(struct vrf *vrf, struct vty *vty, bool uj)
                        if (!json_group) {
                                json_group = json_object_new_object();
                                json_object_object_add(json, grp_str,
-                                               json_group);
+                                                      json_group);
                        }
 
                        json_row = json_object_new_object();
@@ -4950,18 +5013,20 @@ static void pim_show_mlag_up_vrf(struct vrf *vrf, struct vty *vty, bool uj)
                        if (pim_up_mlag_is_local(up)) {
 
                                json_object_array_add(own_list,
-                                       json_object_new_string("local"));
+                                                     json_object_new_string(
+                                                             "local"));
                        }
                        if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)) {
                                json_object_array_add(own_list,
-                                       json_object_new_string("peer"));
+                                                     json_object_new_string(
+                                                             "peer"));
                        }
                        json_object_object_add(json_row, "owners", own_list);
 
                        json_object_int_add(json_row, "localCost",
-                                       pim_up_mlag_local_cost(up));
+                                           pim_up_mlag_local_cost(up));
                        json_object_int_add(json_row, "peerCost",
-                                       pim_up_mlag_peer_cost(up));
+                                           pim_up_mlag_peer_cost(up));
                        if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags))
                                json_object_boolean_false_add(json_row, "df");
                        else
@@ -4983,12 +5048,12 @@ static void pim_show_mlag_up_vrf(struct vrf *vrf, struct vty *vty, bool uj)
                                pim_up_mlag_local_cost(up),
                                pim_up_mlag_peer_cost(up),
                                PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
-                                       ? "n" : "y");
+                               ? "n" : "y");
                }
        }
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                       json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -5261,8 +5326,8 @@ DEFPY (show_ip_pim_upstream,
                return CMD_WARNING;
        }
 
-       if (s_or_g.s_addr != 0) {
-               if (g.s_addr != 0) {
+       if (s_or_g.s_addr != INADDR_ANY) {
+               if (g.s_addr != INADDR_ANY) {
                        sg.src = s_or_g;
                        sg.grp = g;
                } else
@@ -5939,7 +6004,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
                vty_out(vty, "IP Multicast Routing Table\n");
                vty_out(vty, "Flags: S - Sparse, C - Connected, P - Pruned\n");
                vty_out(vty,
-                       "       R - RP-bit set, F - Register flag, T - SPT-bit set\n");
+                       "       R - SGRpt Pruned, F - Register flag, T - SPT-bit set\n");
                vty_out(vty,
                        "\nSource          Group           Flags   Proto  Input            Output           TTL  Uptime\n");
        }
@@ -5953,11 +6018,11 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
                if (!c_oil->installed)
                        continue;
 
-               if (sg->grp.s_addr != 0 &&
-                   sg->grp.s_addr != c_oil->oil.mfcc_mcastgrp.s_addr)
+               if (sg->grp.s_addr != INADDR_ANY
+                   && sg->grp.s_addr != c_oil->oil.mfcc_mcastgrp.s_addr)
                        continue;
-               if (sg->src.s_addr != 0 &&
-                   sg->src.s_addr != c_oil->oil.mfcc_origin.s_addr)
+               if (sg->src.s_addr != INADDR_ANY
+                   && sg->src.s_addr != c_oil->oil.mfcc_origin.s_addr)
                        continue;
 
                pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, grp_str,
@@ -6042,12 +6107,12 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
 
                        /* do not display muted OIFs */
                        if (c_oil->oif_flags[oif_vif_index]
-                                       & PIM_OIF_FLAG_MUTE)
+                           & PIM_OIF_FLAG_MUTE)
                                continue;
 
                        if (c_oil->oil.mfcc_parent == oif_vif_index &&
-                                       !pim_mroute_allow_iif_in_oil(c_oil,
-                                               oif_vif_index))
+                           !pim_mroute_allow_iif_in_oil(c_oil,
+                                                        oif_vif_index))
                                continue;
 
                        ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
@@ -6109,6 +6174,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
                                json_object_object_add(json_oil, out_ifname,
                                                       json_ifp_out);
                        } else {
+                               proto[0] = '\0';
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_PIM) {
                                        strlcpy(proto, "PIM", sizeof(proto));
@@ -6215,8 +6281,8 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
                        pim_time_uptime(
                                oif_uptime, sizeof(oif_uptime),
                                now
-                                       - s_route->c_oil
-                                                 .oif_creation[oif_vif_index]);
+                               - s_route->c_oil
+                               .oif_creation[oif_vif_index]);
                        found_oif = 1;
 
                        if (ifp_out)
@@ -6278,7 +6344,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -6312,8 +6378,8 @@ DEFPY (show_ip_mroute,
                return CMD_WARNING;
        }
 
-       if (s_or_g.s_addr != 0) {
-               if (g.s_addr != 0) {
+       if (s_or_g.s_addr != INADDR_ANY) {
+               if (g.s_addr != INADDR_ANY) {
                        sg.src = s_or_g;
                        sg.grp = g;
                } else
@@ -6609,8 +6675,8 @@ static void show_mroute_summary(struct pim_instance *pim, struct vty *vty,
                                    starg_hw_mroute_cnt + sg_hw_mroute_cnt);
                json_object_int_add(json, "totalNumOfMroutes",
                                    starg_sw_mroute_cnt + starg_hw_mroute_cnt
-                                           + sg_sw_mroute_cnt
-                                           + sg_hw_mroute_cnt);
+                                   + sg_sw_mroute_cnt
+                                   + sg_hw_mroute_cnt);
        }
 }
 
@@ -6796,83 +6862,6 @@ DEFUN (show_ip_ssmpingd,
        return CMD_SUCCESS;
 }
 
-static int pim_rp_cmd_worker(struct pim_instance *pim, struct vty *vty,
-                            const char *rp, const char *group,
-                            const char *plist)
-{
-       int result;
-
-       result = pim_rp_new_config(pim, rp, group, plist);
-
-       if (result == PIM_GROUP_BAD_ADDR_MASK_COMBO) {
-               vty_out(vty, "%% Inconsistent address and mask: %s\n",
-                       group ? group : "No Group Address");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       if (result == PIM_GROUP_BAD_ADDRESS) {
-               vty_out(vty, "%% Bad group address specified: %s\n",
-                       group ? group : "No Group Address");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       if (result == PIM_RP_BAD_ADDRESS) {
-               vty_out(vty, "%% Bad RP address specified: %s\n", rp);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       if (result == PIM_RP_NO_PATH) {
-               vty_out(vty, "%% No Path to RP address specified: %s\n", rp);
-               return CMD_WARNING;
-       }
-
-       if (result == PIM_GROUP_OVERLAP) {
-               vty_out(vty,
-                       "%% Group range specified cannot exact match another\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       if (result == PIM_GROUP_PFXLIST_OVERLAP) {
-               vty_out(vty,
-                       "%% This group is already covered by a RP prefix-list\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       if (result == PIM_RP_PFXLIST_IN_USE) {
-               vty_out(vty,
-                       "%% The same prefix-list cannot be applied to multiple RPs\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return CMD_SUCCESS;
-}
-
-static int pim_cmd_spt_switchover(struct pim_instance *pim,
-                                 enum pim_spt_switchover spt,
-                                 const char *plist)
-{
-       pim->spt.switchover = spt;
-
-       switch (pim->spt.switchover) {
-       case PIM_SPT_IMMEDIATE:
-               XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist);
-
-               pim_upstream_add_lhr_star_pimreg(pim);
-               break;
-       case PIM_SPT_INFINITY:
-               pim_upstream_remove_lhr_star_pimreg(pim, plist);
-
-               XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist);
-
-               if (plist)
-                       pim->spt.plist =
-                               XSTRDUP(MTYPE_PIM_PLIST_NAME, plist);
-               break;
-       }
-
-       return CMD_SUCCESS;
-}
-
 DEFUN (ip_pim_spt_switchover_infinity,
        ip_pim_spt_switchover_infinity_cmd,
        "ip pim spt-switchover infinity-and-beyond",
@@ -6881,8 +6870,45 @@ DEFUN (ip_pim_spt_switchover_infinity,
        "SPT-Switchover\n"
        "Never switch to SPT Tree\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       return pim_cmd_spt_switchover(pim, PIM_SPT_INFINITY, NULL);
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char spt_plist_xpath[XPATH_MAXLEN];
+       char spt_action_xpath[XPATH_MAXLEN];
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
+                FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
+                "frr-routing:ipv4");
+       strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
+               sizeof(spt_plist_xpath));
+
+       snprintf(spt_action_xpath, sizeof(spt_action_xpath),
+                FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
+                "frr-routing:ipv4");
+       strlcat(spt_action_xpath, "/spt-switchover/spt-action",
+               sizeof(spt_action_xpath));
+
+       if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath))
+               nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY,
+                                     NULL);
+       nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
+                             "PIM_SPT_INFINITY");
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (ip_pim_spt_switchover_infinity_plist,
@@ -6895,8 +6921,44 @@ DEFUN (ip_pim_spt_switchover_infinity_plist,
        "Prefix-List to control which groups to switch\n"
        "Prefix-List name\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       return pim_cmd_spt_switchover(pim, PIM_SPT_INFINITY, argv[5]->arg);
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char spt_plist_xpath[XPATH_MAXLEN];
+       char spt_action_xpath[XPATH_MAXLEN];
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
+                FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
+                "frr-routing:ipv4");
+       strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
+               sizeof(spt_plist_xpath));
+
+       snprintf(spt_action_xpath, sizeof(spt_action_xpath),
+                FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
+                "frr-routing:ipv4");
+       strlcat(spt_action_xpath, "/spt-switchover/spt-action",
+               sizeof(spt_action_xpath));
+
+       nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
+                             "PIM_SPT_INFINITY");
+       nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY,
+                             argv[5]->arg);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_pim_spt_switchover_infinity,
@@ -6908,8 +6970,43 @@ DEFUN (no_ip_pim_spt_switchover_infinity,
        "SPT_Switchover\n"
        "Never switch to SPT Tree\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       return pim_cmd_spt_switchover(pim, PIM_SPT_IMMEDIATE, NULL);
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char spt_plist_xpath[XPATH_MAXLEN];
+       char spt_action_xpath[XPATH_MAXLEN];
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
+                FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
+                "frr-routing:ipv4");
+       strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
+               sizeof(spt_plist_xpath));
+
+       snprintf(spt_action_xpath, sizeof(spt_action_xpath),
+                FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
+                "frr-routing:ipv4");
+       strlcat(spt_action_xpath, "/spt-switchover/spt-action",
+               sizeof(spt_action_xpath));
+
+       nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL);
+       nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
+                             "PIM_SPT_IMMEDIATE");
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_pim_spt_switchover_infinity_plist,
@@ -6923,8 +7020,43 @@ DEFUN (no_ip_pim_spt_switchover_infinity_plist,
        "Prefix-List to control which groups to switch\n"
        "Prefix-List name\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       return pim_cmd_spt_switchover(pim, PIM_SPT_IMMEDIATE, NULL);
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char spt_plist_xpath[XPATH_MAXLEN];
+       char spt_action_xpath[XPATH_MAXLEN];
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
+                FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
+                "frr-routing:ipv4");
+       strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
+               sizeof(spt_plist_xpath));
+
+       snprintf(spt_action_xpath, sizeof(spt_action_xpath),
+                FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
+                "frr-routing:ipv4");
+       strlcat(spt_action_xpath, "/spt-switchover/spt-action",
+               sizeof(spt_action_xpath));
+
+       nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL);
+       nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
+                             "PIM_SPT_IMMEDIATE");
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFPY (pim_register_accept_list,
@@ -6936,15 +7068,37 @@ DEFPY (pim_register_accept_list,
        "Only accept registers from a specific source prefix list\n"
        "Prefix-List name\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char reg_alist_xpath[XPATH_MAXLEN];
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(reg_alist_xpath, sizeof(reg_alist_xpath),
+                FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
+                "frr-routing:ipv4");
+       strlcat(reg_alist_xpath, "/register-accept-list",
+               sizeof(reg_alist_xpath));
 
        if (no)
-               XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist);
-       else {
-               XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist);
-               pim->register_plist = XSTRDUP(MTYPE_PIM_PLIST_NAME, word);
-       }
-       return CMD_SUCCESS;
+               nb_cli_enqueue_change(vty, reg_alist_xpath,
+                                     NB_OP_DESTROY, NULL);
+       else
+               nb_cli_enqueue_change(vty, reg_alist_xpath,
+                                     NB_OP_MODIFY, word);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (ip_pim_joinprune_time,
@@ -6955,9 +7109,10 @@ DEFUN (ip_pim_joinprune_time,
        "Join Prune Send Interval\n"
        "Seconds\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       router->t_periodic = atoi(argv[3]->arg);
-       return CMD_SUCCESS;
+       nb_cli_enqueue_change(vty, "/frr-pim:pim/join-prune-interval",
+                             NB_OP_MODIFY, argv[3]->arg);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_pim_joinprune_time,
@@ -6969,9 +7124,15 @@ DEFUN (no_ip_pim_joinprune_time,
        "Join Prune Send Interval\n"
        "Seconds\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       router->t_periodic = PIM_DEFAULT_T_PERIODIC;
-       return CMD_SUCCESS;
+       char jp_default_timer[5];
+
+       snprintf(jp_default_timer, sizeof(jp_default_timer), "%d",
+                PIM_DEFAULT_T_PERIODIC);
+
+       nb_cli_enqueue_change(vty, "/frr-pim:pim/join-prune-interval",
+                             NB_OP_MODIFY, jp_default_timer);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (ip_pim_register_suppress,
@@ -6982,9 +7143,10 @@ DEFUN (ip_pim_register_suppress,
        "Register Suppress Timer\n"
        "Seconds\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       router->register_suppress_time = atoi(argv[3]->arg);
-       return CMD_SUCCESS;
+       nb_cli_enqueue_change(vty, "/frr-pim:pim/register-suppress-time",
+                             NB_OP_MODIFY, argv[3]->arg);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_pim_register_suppress,
@@ -6996,9 +7158,15 @@ DEFUN (no_ip_pim_register_suppress,
        "Register Suppress Timer\n"
        "Seconds\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       router->register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT;
-       return CMD_SUCCESS;
+       char rs_default_timer[5];
+
+       snprintf(rs_default_timer, sizeof(rs_default_timer), "%d",
+                PIM_REGISTER_SUPPRESSION_TIME_DEFAULT);
+
+       nb_cli_enqueue_change(vty, "/frr-pim:pim/register-suppress-time",
+                             NB_OP_MODIFY, rs_default_timer);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (ip_pim_rp_keep_alive,
@@ -7010,9 +7178,32 @@ DEFUN (ip_pim_rp_keep_alive,
        "Keep alive Timer\n"
        "Seconds\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       pim->rp_keep_alive_time = atoi(argv[4]->arg);
-       return CMD_SUCCESS;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char rp_ka_timer_xpath[XPATH_MAXLEN];
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
+                FRR_PIM_XPATH, "frr-pim:pimd", "pim", vrfname);
+       strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
+               sizeof(rp_ka_timer_xpath));
+
+       nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
+                             argv[4]->arg);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_pim_rp_keep_alive,
@@ -7025,9 +7216,36 @@ DEFUN (no_ip_pim_rp_keep_alive,
        "Keep alive Timer\n"
        "Seconds\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       pim->rp_keep_alive_time = PIM_KEEPALIVE_PERIOD;
-       return CMD_SUCCESS;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char rp_ka_timer[5];
+       char rp_ka_timer_xpath[XPATH_MAXLEN];
+
+       snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%d", PIM_KEEPALIVE_PERIOD);
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+
+       snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
+                FRR_PIM_XPATH, "frr-pim:pimd", "pim", vrfname);
+       strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
+               sizeof(rp_ka_timer_xpath));
+
+       nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
+                             rp_ka_timer);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (ip_pim_keep_alive,
@@ -7038,9 +7256,31 @@ DEFUN (ip_pim_keep_alive,
        "Keep alive Timer\n"
        "Seconds\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       pim->keep_alive_time = atoi(argv[3]->arg);
-       return CMD_SUCCESS;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char ka_timer_xpath[XPATH_MAXLEN];
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_XPATH,
+                "frr-pim:pimd", "pim", vrfname);
+       strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
+
+       nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY,
+                             argv[3]->arg);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_pim_keep_alive,
@@ -7052,9 +7292,34 @@ DEFUN (no_ip_pim_keep_alive,
        "Keep alive Timer\n"
        "Seconds\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       pim->keep_alive_time = PIM_KEEPALIVE_PERIOD;
-       return CMD_SUCCESS;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char ka_timer[5];
+       char ka_timer_xpath[XPATH_MAXLEN];
+
+       snprintf(ka_timer, sizeof(ka_timer), "%d", PIM_KEEPALIVE_PERIOD);
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_XPATH,
+                "frr-pim:pimd", "pim", vrfname);
+       strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
+
+       nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY,
+                             ka_timer);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (ip_pim_packets,
@@ -7065,9 +7330,10 @@ DEFUN (ip_pim_packets,
        "packets to process at one time per fd\n"
        "Number of packets\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       router->packet_process = atoi(argv[3]->arg);
-       return CMD_SUCCESS;
+       nb_cli_enqueue_change(vty, "/frr-pim:pim/packets", NB_OP_MODIFY,
+                             argv[3]->arg);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_pim_packets,
@@ -7079,9 +7345,15 @@ DEFUN (no_ip_pim_packets,
        "packets to process at one time per fd\n"
        "Number of packets\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       router->packet_process = PIM_DEFAULT_PACKET_PROCESS;
-       return CMD_SUCCESS;
+       char default_packet[3];
+
+       snprintf(default_packet, sizeof(default_packet), "%d",
+                PIM_DEFAULT_PACKET_PROCESS);
+
+       nb_cli_enqueue_change(vty, "/frr-pim:pim/packets", NB_OP_MODIFY,
+                             default_packet);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFPY (igmp_group_watermark,
@@ -7120,10 +7392,33 @@ DEFUN (ip_pim_v6_secondary,
        "pim multicast routing\n"
        "Send v6 secondary addresses\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       pim->send_v6_secondary = 1;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char send_v6_secondary_xpath[XPATH_MAXLEN];
 
-       return CMD_SUCCESS;
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(send_v6_secondary_xpath, "/send-v6-secondary",
+               sizeof(send_v6_secondary_xpath));
+
+       nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY,
+                             "true");
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_pim_v6_secondary,
@@ -7134,10 +7429,33 @@ DEFUN (no_ip_pim_v6_secondary,
        "pim multicast routing\n"
        "Send v6 secondary addresses\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       pim->send_v6_secondary = 0;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char send_v6_secondary_xpath[XPATH_MAXLEN];
 
-       return CMD_SUCCESS;
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(send_v6_secondary_xpath, "/send-v6-secondary",
+               sizeof(send_v6_secondary_xpath));
+
+       nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY,
+                             "false");
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (ip_pim_rp,
@@ -7149,15 +7467,66 @@ DEFUN (ip_pim_rp,
        "ip address of RP\n"
        "Group Address range to cover\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       int idx_ipv4 = 3;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       int idx_rp = 3, idx_group = 4;
+       char rp_group_xpath[XPATH_MAXLEN];
+       int result = 0;
+       struct prefix group;
+       struct in_addr rp_addr;
+       const char *group_str =
+               (argc == 5) ? argv[idx_group]->arg : "224.0.0.0/4";
 
-       if (argc == (idx_ipv4 + 1))
-               return pim_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg, NULL,
-                                        NULL);
-       else
-               return pim_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg,
-                                        argv[idx_ipv4 + 1]->arg, NULL);
+       result = str2prefix(group_str, &group);
+       if (result) {
+               struct prefix temp;
+
+               prefix_copy(&temp, &group);
+               apply_mask(&temp);
+               if (!prefix_same(&group, &temp)) {
+                       vty_out(vty, "%% Inconsistent address and mask: %s\n",
+                               group_str);
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+       }
+
+       if (!result) {
+               vty_out(vty, "%% Bad group address specified: %s\n",
+                       group_str);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       result = inet_pton(AF_INET, argv[idx_rp]->arg, &rp_addr);
+       if (result <= 0) {
+               vty_out(vty, "%% Bad RP address specified: %s\n",
+                       argv[idx_rp]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(rp_group_xpath, sizeof(rp_group_xpath),
+                FRR_PIM_STATIC_RP_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4",
+                argv[idx_rp]->arg);
+       strlcat(rp_group_xpath, "/group-list", sizeof(rp_group_xpath));
+
+       nb_cli_enqueue_change(vty, rp_group_xpath, NB_OP_CREATE, group_str);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (ip_pim_rp_prefix_list,
@@ -7170,33 +7539,36 @@ DEFUN (ip_pim_rp_prefix_list,
        "group prefix-list filter\n"
        "Name of a prefix-list\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       return pim_rp_cmd_worker(pim, vty, argv[3]->arg, NULL, argv[5]->arg);
-}
+       int idx_rp = 3, idx_plist = 5;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char rp_plist_xpath[XPATH_MAXLEN];
 
-static int pim_no_rp_cmd_worker(struct pim_instance *pim, struct vty *vty,
-                               const char *rp, const char *group,
-                               const char *plist)
-{
-       int result = pim_rp_del_config(pim, rp, group, plist);
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
 
-       if (result == PIM_GROUP_BAD_ADDRESS) {
-               vty_out(vty, "%% Bad group address specified: %s\n",
-                       group ? group : "No Group Address");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
 
-       if (result == PIM_RP_BAD_ADDRESS) {
-               vty_out(vty, "%% Bad RP address specified: %s\n", rp);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
 
-       if (result == PIM_RP_NOT_FOUND) {
-               vty_out(vty, "%% Unable to find specified RP\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       snprintf(rp_plist_xpath, sizeof(rp_plist_xpath),
+                FRR_PIM_STATIC_RP_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4",
+                argv[idx_rp]->arg);
+       strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath));
 
-       return CMD_SUCCESS;
+       nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY,
+                             argv[idx_plist]->arg);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_pim_rp,
@@ -7209,15 +7581,55 @@ DEFUN (no_ip_pim_rp,
        "ip address of RP\n"
        "Group Address range to cover\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       int idx_ipv4 = 4, idx_group = 0;
+       int idx_rp = 4, idx_group = 5;
+       const char *group_str =
+               (argc == 6) ? argv[idx_group]->arg : "224.0.0.0/4";
+       char group_list_xpath[XPATH_MAXLEN + 32];
+       char group_xpath[XPATH_MAXLEN + 64];
+       char rp_xpath[XPATH_MAXLEN];
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       const struct lyd_node *group_dnode;
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4",
+                argv[idx_rp]->arg);
+
+       snprintf(group_list_xpath, sizeof(group_list_xpath), "%s/group-list",
+                rp_xpath);
+
+       snprintf(group_xpath, sizeof(group_xpath), "%s[.='%s']",
+                group_list_xpath, group_str);
 
-       if (argv_find(argv, argc, "A.B.C.D/M", &idx_group))
-               return pim_no_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg,
-                                           argv[idx_group]->arg, NULL);
+       if (!yang_dnode_exists(vty->candidate_config->dnode, group_xpath)) {
+               vty_out(vty, "%% Unable to find specified RP\n");
+               return NB_OK;
+       }
+
+       group_dnode = yang_dnode_get(vty->candidate_config->dnode, group_xpath);
+
+       if (yang_is_last_list_dnode(group_dnode))
+               nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL);
        else
-               return pim_no_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg, NULL,
-                                           NULL);
+               nb_cli_enqueue_change(vty, group_list_xpath, NB_OP_DESTROY,
+                                     group_str);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_pim_rp_prefix_list,
@@ -7231,32 +7643,52 @@ DEFUN (no_ip_pim_rp_prefix_list,
        "group prefix-list filter\n"
        "Name of a prefix-list\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       return pim_no_rp_cmd_worker(pim, vty, argv[4]->arg, NULL, argv[6]->arg);
-}
+       int idx_rp = 4;
+       int idx_plist = 6;
+       char rp_xpath[XPATH_MAXLEN];
+       char plist_xpath[XPATH_MAXLEN];
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       const struct lyd_node *plist_dnode;
+       const char *plist;
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
 
-static int pim_ssm_cmd_worker(struct pim_instance *pim, struct vty *vty,
-                             const char *plist)
-{
-       int result = pim_ssm_range_set(pim, pim->vrf_id, plist);
-       int ret = CMD_WARNING_CONFIG_FAILED;
+       snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4",
+                argv[idx_rp]->arg);
 
-       if (result == PIM_SSM_ERR_NONE)
-               return CMD_SUCCESS;
+       snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4",
+                argv[idx_rp]->arg);
+       strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath));
 
-       switch (result) {
-       case PIM_SSM_ERR_NO_VRF:
-               vty_out(vty, "%% VRF doesn't exist\n");
-               break;
-       case PIM_SSM_ERR_DUP:
-               vty_out(vty, "%% duplicate config\n");
-               ret = CMD_WARNING;
-               break;
-       default:
-               vty_out(vty, "%% ssm range config failed\n");
+       plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath);
+       if (!plist_dnode) {
+               vty_out(vty, "%% Unable to find specified RP\n");
+               return NB_OK;
+       }
+
+       plist = yang_dnode_get_string(plist_dnode, plist_xpath);
+       if (strcmp(argv[idx_plist]->arg, plist)) {
+               vty_out(vty, "%% Unable to find specified RP\n");
+               return NB_OK;
        }
 
-       return ret;
+       nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (ip_pim_ssm_prefix_list,
@@ -7268,8 +7700,30 @@ DEFUN (ip_pim_ssm_prefix_list,
        "group range prefix-list filter\n"
        "Name of a prefix-list\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       return pim_ssm_cmd_worker(pim, vty, argv[4]->arg);
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char ssm_plist_xpath[XPATH_MAXLEN];
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath));
+
+       nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, argv[4]->arg);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_pim_ssm_prefix_list,
@@ -7281,8 +7735,31 @@ DEFUN (no_ip_pim_ssm_prefix_list,
        "Source Specific Multicast\n"
        "group range prefix-list filter\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       return pim_ssm_cmd_worker(pim, vty, NULL);
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char ssm_plist_xpath[XPATH_MAXLEN];
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath));
+
+       nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_pim_ssm_prefix_list_name,
@@ -7295,11 +7772,50 @@ DEFUN (no_ip_pim_ssm_prefix_list_name,
        "group range prefix-list filter\n"
        "Name of a prefix-list\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       struct pim_ssm *ssm = pim->ssm_info;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       const struct lyd_node *ssm_plist_dnode;
+       char ssm_plist_xpath[XPATH_MAXLEN];
+       const char *ssm_plist_name;
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
 
-       if (ssm->plist_name && !strcmp(ssm->plist_name, argv[5]->arg))
-               return pim_ssm_cmd_worker(pim, vty, NULL);
+
+       snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath));
+       ssm_plist_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                        ssm_plist_xpath);
+
+       if (!ssm_plist_dnode) {
+               vty_out(vty,
+                       "%% pim ssm prefix-list %s doesn't exist\n",
+                       argv[5]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       ssm_plist_name = yang_dnode_get_string(ssm_plist_dnode, ".");
+
+       if (ssm_plist_name && !strcmp(ssm_plist_name, argv[5]->arg)) {
+               nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY,
+                                     NULL);
+
+               return nb_cli_apply_changes(vty, NULL);
+       }
 
        vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", argv[5]->arg);
 
@@ -7318,7 +7834,7 @@ static void ip_pim_ssm_show_group_range(struct pim_instance *pim,
                json = json_object_new_object();
                json_object_string_add(json, "ssmGroups", range_str);
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else
                vty_out(vty, "SSM group range : %s\n", range_str);
@@ -7370,7 +7886,7 @@ static void ip_pim_ssm_show_group_type(struct pim_instance *pim,
                json = json_object_new_object();
                json_object_string_add(json, "groupType", type_str);
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else
                vty_out(vty, "Group type : %s\n", type_str);
@@ -7428,27 +7944,35 @@ DEFUN (ip_ssmpingd,
        CONF_SSMPINGD_STR
        "Source address\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
        int idx_ipv4 = 2;
-       int result;
-       struct in_addr source_addr;
        const char *source_str = (argc == 3) ? argv[idx_ipv4]->arg : "0.0.0.0";
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char ssmpingd_ip_xpath[XPATH_MAXLEN];
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
 
-       result = inet_pton(AF_INET, source_str, &source_addr);
-       if (result <= 0) {
-               vty_out(vty, "%% Bad source address %s: errno=%d: %s\n",
-                       source_str, errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(ssmpingd_ip_xpath, "/ssm-pingd-source-ip",
+               sizeof(ssmpingd_ip_xpath));
 
-       result = pim_ssmpingd_start(pim, source_addr);
-       if (result) {
-               vty_out(vty, "%% Failure starting ssmpingd for source %s: %d\n",
-                       source_str, result);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       nb_cli_enqueue_change(vty, ssmpingd_ip_xpath, NB_OP_CREATE,
+                             source_str);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_ssmpingd,
@@ -7459,27 +7983,35 @@ DEFUN (no_ip_ssmpingd,
        CONF_SSMPINGD_STR
        "Source address\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
        int idx_ipv4 = 3;
-       int result;
-       struct in_addr source_addr;
        const char *source_str = (argc == 4) ? argv[idx_ipv4]->arg : "0.0.0.0";
+       char ssmpingd_ip_xpath[XPATH_MAXLEN];
 
-       result = inet_pton(AF_INET, source_str, &source_addr);
-       if (result <= 0) {
-               vty_out(vty, "%% Bad source address %s: errno=%d: %s\n",
-                       source_str, errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
 
-       result = pim_ssmpingd_stop(pim, source_addr);
-       if (result) {
-               vty_out(vty, "%% Failure stopping ssmpingd for source %s: %d\n",
-                       source_str, result);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(ssmpingd_ip_xpath, "/ssm-pingd-source-ip",
+               sizeof(ssmpingd_ip_xpath));
 
-       return CMD_SUCCESS;
+       nb_cli_enqueue_change(vty, ssmpingd_ip_xpath, NB_OP_DESTROY,
+                             source_str);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (ip_pim_ecmp,
@@ -7489,10 +8021,29 @@ DEFUN (ip_pim_ecmp,
        "pim multicast routing\n"
        "Enable PIM ECMP \n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       pim->ecmp_enable = true;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char ecmp_xpath[XPATH_MAXLEN];
 
-       return CMD_SUCCESS;
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH,
+                "frr-pim:pimd", "pim", vrfname);
+       strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath));
+
+       nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true");
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_pim_ecmp,
@@ -7503,10 +8054,30 @@ DEFUN (no_ip_pim_ecmp,
        "pim multicast routing\n"
        "Disable PIM ECMP \n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       pim->ecmp_enable = false;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char ecmp_xpath[XPATH_MAXLEN];
 
-       return CMD_SUCCESS;
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH,
+                "frr-pim:pimd", "pim", vrfname);
+       strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath));
+
+       nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false");
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (ip_pim_ecmp_rebalance,
@@ -7517,11 +8088,37 @@ DEFUN (ip_pim_ecmp_rebalance,
        "Enable PIM ECMP \n"
        "Enable PIM ECMP Rebalance\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       pim->ecmp_enable = true;
-       pim->ecmp_rebalance_enable = true;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char ecmp_xpath[XPATH_MAXLEN];
+       char ecmp_rebalance_xpath[XPATH_MAXLEN];
 
-       return CMD_SUCCESS;
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH,
+                "frr-pim:pimd", "pim", vrfname);
+       strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath));
+       snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath),
+                FRR_PIM_XPATH,
+                "frr-pim:pimd", "pim", vrfname);
+       strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance",
+               sizeof(ecmp_rebalance_xpath));
+
+       nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true");
+       nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "true");
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_pim_ecmp_rebalance,
@@ -7533,46 +8130,32 @@ DEFUN (no_ip_pim_ecmp_rebalance,
        "Disable PIM ECMP \n"
        "Disable PIM ECMP Rebalance\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       pim->ecmp_rebalance_enable = false;
-
-       return CMD_SUCCESS;
-}
-
-static int pim_cmd_igmp_start(struct vty *vty, struct interface *ifp)
-{
-       struct pim_interface *pim_ifp;
-       struct pim_instance *pim;
-       uint8_t need_startup = 0;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char ecmp_rebalance_xpath[XPATH_MAXLEN];
 
-       pim_ifp = ifp->info;
-
-       if (!pim_ifp) {
-               pim = pim_get_pim_instance(ifp->vrf_id);
-               /* Limit mcast interfaces to number of vifs available */
-               if (pim->mcast_if_count == MAXVIFS) {
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
                        vty_out(vty,
-                               "Max multicast interfaces(%d) Reached. Could not enable IGMP on interface %s\n",
-                               MAXVIFS, ifp->name);
+                               "%% Failed to get vrf dnode in candidate db\n");
                        return CMD_WARNING_CONFIG_FAILED;
                }
-               (void)pim_if_new(ifp, true, false, false, false);
-               need_startup = 1;
-       } else {
-               if (!PIM_IF_TEST_IGMP(pim_ifp->options)) {
-                       PIM_IF_DO_IGMP(pim_ifp->options);
-                       need_startup = 1;
-               }
-       }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
 
-       /* 'ip igmp' executed multiple times, with need_startup
-         avoid multiple if add all and membership refresh */
-       if (need_startup) {
-               pim_if_addr_add_all(ifp);
-               pim_if_membership_refresh(ifp);
-       }
+       snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath),
+                FRR_PIM_XPATH,
+                "frr-pim:pimd", "pim", vrfname);
+       strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance",
+               sizeof(ecmp_rebalance_xpath));
 
-       return CMD_SUCCESS;
+       nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "false");
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (interface_ip_igmp,
@@ -7581,9 +8164,9 @@ DEFUN (interface_ip_igmp,
        IP_STR
        IFACE_IGMP_STR)
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
+       nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, "true");
 
-       return pim_cmd_igmp_start(vty, ifp);
+       return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
 }
 
 DEFUN (interface_no_ip_igmp,
@@ -7593,23 +8176,28 @@ DEFUN (interface_no_ip_igmp,
        IP_STR
        IFACE_IGMP_STR)
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
+       const struct lyd_node *pim_enable_dnode;
+       char pim_if_xpath[XPATH_MAXLEN + 20];
 
-       if (!pim_ifp)
-               return CMD_SUCCESS;
-
-       PIM_IF_DONT_IGMP(pim_ifp->options);
-
-       pim_if_membership_clear(ifp);
+       snprintf(pim_if_xpath, sizeof(pim_if_xpath),
+                "%s/frr-pim:pim", VTY_CURR_XPATH);
 
-       pim_if_addr_del_all_igmp(ifp);
-
-       if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
-               pim_if_delete(ifp);
+       pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                         "%s/pim-enable", pim_if_xpath);
+       if (!pim_enable_dnode) {
+               nb_cli_enqueue_change(vty, pim_if_xpath, NB_OP_DESTROY, NULL);
+               nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+       } else {
+               if (!yang_dnode_get_bool(pim_enable_dnode, ".")) {
+                       nb_cli_enqueue_change(vty, pim_if_xpath, NB_OP_DESTROY,
+                                             NULL);
+                       nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+               } else
+                       nb_cli_enqueue_change(vty, "./igmp-enable",
+                                             NB_OP_MODIFY, "false");
        }
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
 }
 
 DEFUN (interface_ip_igmp_join,
@@ -7621,46 +8209,28 @@ DEFUN (interface_ip_igmp_join,
        "Multicast group address\n"
        "Source address\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       int idx_ipv4 = 3;
-       int idx_ipv4_2 = 4;
-       const char *group_str;
+       int idx_group = 3;
+       int idx_source = 4;
        const char *source_str;
-       struct in_addr group_addr;
-       struct in_addr source_addr;
-       int result;
+       char xpath[XPATH_MAXLEN];
 
-       /* Group address */
-       group_str = argv[idx_ipv4]->arg;
-       result = inet_pton(AF_INET, group_str, &group_addr);
-       if (result <= 0) {
-               vty_out(vty, "Bad group address %s: errno=%d: %s\n", group_str,
-                       errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       if (argc == 5) {
+               source_str = argv[idx_source]->arg;
 
-       /* Source address */
-       if (argc == (idx_ipv4_2 + 1)) {
-               source_str = argv[idx_ipv4_2]->arg;
-               result = inet_pton(AF_INET, source_str, &source_addr);
-               if (result <= 0) {
-                       vty_out(vty, "Bad source address %s: errno=%d: %s\n",
-                               source_str, errno, safe_strerror(errno));
+               if (strcmp(source_str, "0.0.0.0") == 0) {
+                       vty_out(vty, "Bad source address %s\n",
+                               argv[idx_source]->arg);
                        return CMD_WARNING_CONFIG_FAILED;
                }
-               /* Reject 0.0.0.0. Reserved for any source. */
-               if (source_addr.s_addr == INADDR_ANY) {
-                       vty_out(vty, "Bad source address %s\n", source_str);
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
-       } else {
-               source_addr.s_addr = INADDR_ANY;
-       }
+       } else
+               source_str = "0.0.0.0";
 
-       CMD_FERR_RETURN(pim_if_igmp_join_add(ifp, group_addr, source_addr),
-                       "Failure joining IGMP group: $ERR");
+       snprintf(xpath, sizeof(xpath), FRR_IGMP_JOIN_XPATH,
+                "frr-routing:ipv4", argv[idx_group]->arg, source_str);
 
-       return CMD_SUCCESS;
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (interface_no_ip_igmp_join,
@@ -7673,190 +8243,30 @@ DEFUN (interface_no_ip_igmp_join,
        "Multicast group address\n"
        "Source address\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       int idx_ipv4 = 4;
-       int idx_ipv4_2 = 5;
-       const char *group_str;
+       int idx_group = 4;
+       int idx_source = 5;
        const char *source_str;
-       struct in_addr group_addr;
-       struct in_addr source_addr;
-       int result;
+       char xpath[XPATH_MAXLEN];
 
-       /* Group address */
-       group_str = argv[idx_ipv4]->arg;
-       result = inet_pton(AF_INET, group_str, &group_addr);
-       if (result <= 0) {
-               vty_out(vty, "Bad group address %s: errno=%d: %s\n", group_str,
-                       errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       if (argc == 6) {
+               source_str = argv[idx_source]->arg;
 
-       /* Source address */
-       if (argc == (idx_ipv4_2 + 1)) {
-               source_str = argv[idx_ipv4_2]->arg;
-               result = inet_pton(AF_INET, source_str, &source_addr);
-               if (result <= 0) {
-                       vty_out(vty, "Bad source address %s: errno=%d: %s\n",
-                               source_str, errno, safe_strerror(errno));
+               if (strcmp(source_str, "0.0.0.0") == 0) {
+                       vty_out(vty, "Bad source address %s\n",
+                               argv[idx_source]->arg);
                        return CMD_WARNING_CONFIG_FAILED;
                }
-               /* Reject 0.0.0.0. Reserved for any source. */
-               if (source_addr.s_addr == INADDR_ANY) {
-                       vty_out(vty, "Bad source address %s\n", source_str);
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
-       } else {
-               source_str = "*";
-               source_addr.s_addr = INADDR_ANY;
-       }
-
-       result = pim_if_igmp_join_del(ifp, group_addr, source_addr);
-       if (result) {
-               vty_out(vty,
-                       "%% Failure leaving IGMP group %s source %s on interface %s: %d\n",
-                       group_str, source_str, ifp->name, result);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return CMD_SUCCESS;
-}
-
-/*
-  CLI reconfiguration affects the interface level (struct pim_interface).
-  This function propagates the reconfiguration to every active socket
-  for that interface.
- */
-static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp)
-{
-       struct interface *ifp;
-       struct pim_interface *pim_ifp;
-
-       zassert(igmp);
-
-       /* other querier present? */
-
-       if (igmp->t_other_querier_timer)
-               return;
-
-       /* this is the querier */
-
-       zassert(igmp->interface);
-       zassert(igmp->interface->info);
-
-       ifp = igmp->interface;
-       pim_ifp = ifp->info;
-
-       if (PIM_DEBUG_IGMP_TRACE) {
-               char ifaddr_str[INET_ADDRSTRLEN];
-               pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
-                              sizeof(ifaddr_str));
-               zlog_debug("%s: Querier %s on %s reconfig query_interval=%d",
-                          __func__, ifaddr_str, ifp->name,
-                          pim_ifp->igmp_default_query_interval);
-       }
-
-       /*
-         igmp_startup_mode_on() will reset QQI:
-
-         igmp->querier_query_interval = pim_ifp->igmp_default_query_interval;
-       */
-       igmp_startup_mode_on(igmp);
-}
-
-static void igmp_sock_query_reschedule(struct igmp_sock *igmp)
-{
-       if (igmp->mtrace_only)
-               return;
-
-       if (igmp->t_igmp_query_timer) {
-               /* other querier present */
-               zassert(igmp->t_igmp_query_timer);
-               zassert(!igmp->t_other_querier_timer);
-
-               pim_igmp_general_query_off(igmp);
-               pim_igmp_general_query_on(igmp);
-
-               zassert(igmp->t_igmp_query_timer);
-               zassert(!igmp->t_other_querier_timer);
-       } else {
-               /* this is the querier */
-
-               zassert(!igmp->t_igmp_query_timer);
-               zassert(igmp->t_other_querier_timer);
-
-               pim_igmp_other_querier_timer_off(igmp);
-               pim_igmp_other_querier_timer_on(igmp);
-
-               zassert(!igmp->t_igmp_query_timer);
-               zassert(igmp->t_other_querier_timer);
-       }
-}
-
-static void change_query_interval(struct pim_interface *pim_ifp,
-                                 int query_interval)
-{
-       struct listnode *sock_node;
-       struct igmp_sock *igmp;
-
-       pim_ifp->igmp_default_query_interval = query_interval;
-
-       for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
-               igmp_sock_query_interval_reconfig(igmp);
-               igmp_sock_query_reschedule(igmp);
-       }
-}
-
-static void change_query_max_response_time(struct pim_interface *pim_ifp,
-                                          int query_max_response_time_dsec)
-{
-       struct listnode *sock_node;
-       struct igmp_sock *igmp;
-
-       pim_ifp->igmp_query_max_response_time_dsec =
-               query_max_response_time_dsec;
-
-       /*
-         Below we modify socket/group/source timers in order to quickly
-         reflect the change. Otherwise, those timers would eventually catch
-         up.
-        */
-
-       /* scan all sockets */
-       for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
-               struct listnode *grp_node;
-               struct igmp_group *grp;
-
-               /* reschedule socket general query */
-               igmp_sock_query_reschedule(igmp);
-
-               /* scan socket groups */
-               for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grp_node,
-                                         grp)) {
-                       struct listnode *src_node;
-                       struct igmp_source *src;
+       } else
+               source_str = "0.0.0.0";
 
-                       /* reset group timers for groups in EXCLUDE mode */
-                       if (grp->group_filtermode_isexcl) {
-                               igmp_group_reset_gmi(grp);
-                       }
+       snprintf(xpath, sizeof(xpath), FRR_IGMP_JOIN_XPATH,
+                "frr-routing:ipv4", argv[idx_group]->arg, source_str);
 
-                       /* scan group sources */
-                       for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
-                                                 src_node, src)) {
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
 
-                               /* reset source timers for sources with running
-                                * timers */
-                               if (src->t_source_timer) {
-                                       igmp_source_reset_gmi(igmp, grp, src);
-                               }
-                       }
-               }
-       }
+       return nb_cli_apply_changes(vty, NULL);
 }
 
-#define IGMP_QUERY_INTERVAL_MIN (1)
-#define IGMP_QUERY_INTERVAL_MAX (1800)
-
 DEFUN (interface_ip_igmp_query_interval,
        interface_ip_igmp_query_interval_cmd,
        "ip igmp query-interval (1-1800)",
@@ -7865,50 +8275,24 @@ DEFUN (interface_ip_igmp_query_interval,
        IFACE_IGMP_QUERY_INTERVAL_STR
        "Query interval in seconds\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
-       int query_interval;
-       int query_interval_dsec;
-       int ret;
-
-       if (!pim_ifp) {
-               ret = pim_cmd_igmp_start(vty, ifp);
-               if (ret != CMD_SUCCESS)
-                       return ret;
-               pim_ifp = ifp->info;
-       }
+       const struct lyd_node *pim_enable_dnode;
 
-       query_interval = atoi(argv[3]->arg);
-       query_interval_dsec = 10 * query_interval;
-
-       /*
-         It seems we don't need to check bounds since command.c does it
-         already, but we verify them anyway for extra safety.
-       */
-       if (query_interval < IGMP_QUERY_INTERVAL_MIN) {
-               vty_out(vty,
-                       "General query interval %d lower than minimum %d\n",
-                       query_interval, IGMP_QUERY_INTERVAL_MIN);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-       if (query_interval > IGMP_QUERY_INTERVAL_MAX) {
-               vty_out(vty,
-                       "General query interval %d higher than maximum %d\n",
-                       query_interval, IGMP_QUERY_INTERVAL_MAX);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       if (query_interval_dsec <= pim_ifp->igmp_query_max_response_time_dsec) {
-               vty_out(vty,
-                       "Can't set general query interval %d dsec <= query max response time %d dsec.\n",
-                       query_interval_dsec,
-                       pim_ifp->igmp_query_max_response_time_dsec);
-               return CMD_WARNING_CONFIG_FAILED;
+       pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                         "%s/frr-pim:pim/pim-enable",
+                                         VTY_CURR_XPATH);
+       if (!pim_enable_dnode) {
+               nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
+                                     "true");
+       } else {
+               if (!yang_dnode_get_bool(pim_enable_dnode, "."))
+                       nb_cli_enqueue_change(vty, "./igmp-enable",
+                                             NB_OP_MODIFY, "true");
        }
 
-       change_query_interval(pim_ifp, query_interval);
+       nb_cli_enqueue_change(vty, "./query-interval", NB_OP_MODIFY,
+                             argv[3]->arg);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
 }
 
 DEFUN (interface_no_ip_igmp_query_interval,
@@ -7918,28 +8302,16 @@ DEFUN (interface_no_ip_igmp_query_interval,
        IP_STR
        IFACE_IGMP_STR
        IFACE_IGMP_QUERY_INTERVAL_STR)
-{
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
-       int default_query_interval_dsec;
-
-       if (!pim_ifp)
-               return CMD_SUCCESS;
-
-       default_query_interval_dsec = IGMP_GENERAL_QUERY_INTERVAL * 10;
+{
+       char default_query_interval[5];
 
-       if (default_query_interval_dsec
-           <= pim_ifp->igmp_query_max_response_time_dsec) {
-               vty_out(vty,
-                       "Can't set default general query interval %d dsec <= query max response time %d dsec.\n",
-                       default_query_interval_dsec,
-                       pim_ifp->igmp_query_max_response_time_dsec);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       snprintf(default_query_interval, sizeof(default_query_interval), "%d",
+                IGMP_GENERAL_QUERY_INTERVAL);
 
-       change_query_interval(pim_ifp, IGMP_GENERAL_QUERY_INTERVAL);
+       nb_cli_enqueue_change(vty, "./query-interval", NB_OP_MODIFY,
+                             default_query_interval);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
 }
 
 DEFUN (interface_ip_igmp_version,
@@ -7950,36 +8322,11 @@ DEFUN (interface_ip_igmp_version,
        "IGMP version\n"
        "IGMP version number\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
-       int igmp_version, old_version = 0;
-       int ret;
-
-       if (!pim_ifp) {
-               ret = pim_cmd_igmp_start(vty, ifp);
-               if (ret != CMD_SUCCESS)
-                       return ret;
-               pim_ifp = ifp->info;
-       }
-
-       igmp_version = atoi(argv[3]->arg);
-       old_version = pim_ifp->igmp_version;
-       pim_ifp->igmp_version = igmp_version;
-
-       // Check if IGMP is Enabled otherwise, enable on interface
-       if (!PIM_IF_TEST_IGMP(pim_ifp->options)) {
-               PIM_IF_DO_IGMP(pim_ifp->options);
-               pim_if_addr_add_all(ifp);
-               pim_if_membership_refresh(ifp);
-               old_version = igmp_version;
-               // avoid refreshing membership again.
-       }
-       /* Current and new version is different refresh existing
-          membership. Going from 3 -> 2 or 2 -> 3. */
-       if (old_version != igmp_version)
-               pim_if_membership_refresh(ifp);
+       nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
+                             "true");
+       nb_cli_enqueue_change(vty, "./version", NB_OP_MODIFY, argv[3]->arg);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
 }
 
 DEFUN (interface_no_ip_igmp_version,
@@ -7991,20 +8338,11 @@ DEFUN (interface_no_ip_igmp_version,
        "IGMP version\n"
        "IGMP version number\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
+       nb_cli_enqueue_change(vty, "./version", NB_OP_DESTROY, NULL);
 
-       if (!pim_ifp)
-               return CMD_SUCCESS;
-
-       pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
-
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
 }
 
-#define IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC (10)
-#define IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC (250)
-
 DEFUN (interface_ip_igmp_query_max_response_time,
        interface_ip_igmp_query_max_response_time_cmd,
        "ip igmp query-max-response-time (10-250)",
@@ -8013,32 +8351,25 @@ DEFUN (interface_ip_igmp_query_max_response_time,
        IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR
        "Query response value in deci-seconds\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
-       int query_max_response_time;
-       int ret;
-
-       if (!pim_ifp) {
-               ret = pim_cmd_igmp_start(vty, ifp);
-               if (ret != CMD_SUCCESS)
-                       return ret;
-               pim_ifp = ifp->info;
-       }
+       const struct lyd_node *pim_enable_dnode;
 
-       query_max_response_time = atoi(argv[3]->arg);
+       pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                         "%s/frr-pim:pim/pim-enable",
+                                         VTY_CURR_XPATH);
 
-       if (query_max_response_time
-           >= pim_ifp->igmp_default_query_interval * 10) {
-               vty_out(vty,
-                       "Can't set query max response time %d sec >= general query interval %d sec\n",
-                       query_max_response_time,
-                       pim_ifp->igmp_default_query_interval);
-               return CMD_WARNING_CONFIG_FAILED;
+       if (!pim_enable_dnode) {
+               nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
+                                     "true");
+       } else {
+               if (!yang_dnode_get_bool(pim_enable_dnode, "."))
+                       nb_cli_enqueue_change(vty, "./igmp-enable",
+                                             NB_OP_MODIFY, "true");
        }
 
-       change_query_max_response_time(pim_ifp, query_max_response_time);
+       nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
+                             argv[3]->arg);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
 }
 
 DEFUN (interface_no_ip_igmp_query_max_response_time,
@@ -8050,21 +8381,17 @@ DEFUN (interface_no_ip_igmp_query_max_response_time,
        IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR
        "Time for response in deci-seconds\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
-
-       if (!pim_ifp)
-               return CMD_SUCCESS;
+       char default_query_max_response_time[4];
 
-       change_query_max_response_time(pim_ifp,
-                                      IGMP_QUERY_MAX_RESPONSE_TIME_DSEC);
+       snprintf(default_query_max_response_time,
+                sizeof(default_query_max_response_time),
+                "%d", IGMP_QUERY_MAX_RESPONSE_TIME_DSEC);
 
-       return CMD_SUCCESS;
+       nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
+                             default_query_max_response_time);
+       return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
 }
 
-#define IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC (10)
-#define IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC (250)
-
 DEFUN_HIDDEN (interface_ip_igmp_query_max_response_time_dsec,
              interface_ip_igmp_query_max_response_time_dsec_cmd,
              "ip igmp query-max-response-time-dsec (10-250)",
@@ -8073,34 +8400,24 @@ DEFUN_HIDDEN (interface_ip_igmp_query_max_response_time_dsec,
              IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR
              "Query response value in deciseconds\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
-       int query_max_response_time_dsec;
-       int default_query_interval_dsec;
-       int ret;
-
-       if (!pim_ifp) {
-               ret = pim_cmd_igmp_start(vty, ifp);
-               if (ret != CMD_SUCCESS)
-                       return ret;
-               pim_ifp = ifp->info;
-       }
+       const struct lyd_node *pim_enable_dnode;
 
-       query_max_response_time_dsec = atoi(argv[4]->arg);
-
-       default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval;
-
-       if (query_max_response_time_dsec >= default_query_interval_dsec) {
-               vty_out(vty,
-                       "Can't set query max response time %d dsec >= general query interval %d dsec\n",
-                       query_max_response_time_dsec,
-                       default_query_interval_dsec);
-               return CMD_WARNING_CONFIG_FAILED;
+       pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                         "%s/frr-pim:pim/pim-enable",
+                                         VTY_CURR_XPATH);
+       if (!pim_enable_dnode) {
+               nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
+                                     "true");
+       } else {
+               if (!yang_dnode_get_bool(pim_enable_dnode, "."))
+                       nb_cli_enqueue_change(vty, "./igmp-enable",
+                                             NB_OP_MODIFY, "true");
        }
 
-       change_query_max_response_time(pim_ifp, query_max_response_time_dsec);
+       nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
+                             argv[3]->arg);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
 }
 
 DEFUN_HIDDEN (interface_no_ip_igmp_query_max_response_time_dsec,
@@ -8111,21 +8428,18 @@ DEFUN_HIDDEN (interface_no_ip_igmp_query_max_response_time_dsec,
              IFACE_IGMP_STR
              IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR)
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
+       char default_query_max_response_time[4];
 
-       if (!pim_ifp)
-               return CMD_SUCCESS;
+       snprintf(default_query_max_response_time,
+                sizeof(default_query_max_response_time),
+                "%d", IGMP_QUERY_MAX_RESPONSE_TIME_DSEC);
 
-       change_query_max_response_time(pim_ifp,
-                                      IGMP_QUERY_MAX_RESPONSE_TIME_DSEC);
+       nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
+                             default_query_max_response_time);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
 }
 
-#define IGMP_LAST_MEMBER_QUERY_COUNT_MIN (1)
-#define IGMP_LAST_MEMBER_QUERY_COUNT_MAX (7)
-
 DEFUN (interface_ip_igmp_last_member_query_count,
        interface_ip_igmp_last_member_query_count_cmd,
        "ip igmp last-member-query-count (1-7)",
@@ -8134,23 +8448,24 @@ DEFUN (interface_ip_igmp_last_member_query_count,
        IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR
        "Last member query count\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
-       int last_member_query_count;
-       int ret;
+       const struct lyd_node *pim_enable_dnode;
 
-       if (!pim_ifp) {
-               ret = pim_cmd_igmp_start(vty, ifp);
-               if (ret != CMD_SUCCESS)
-                       return ret;
-               pim_ifp = ifp->info;
+       pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                         "%s/frr-pim:pim/pim-enable",
+                                         VTY_CURR_XPATH);
+       if (!pim_enable_dnode) {
+               nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
+                                     "true");
+       } else {
+               if (!yang_dnode_get_bool(pim_enable_dnode, "."))
+                       nb_cli_enqueue_change(vty, "./igmp-enable",
+                                             NB_OP_MODIFY, "true");
        }
 
-       last_member_query_count = atoi(argv[3]->arg);
+       nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_MODIFY,
+                             argv[3]->arg);
 
-       pim_ifp->igmp_last_member_query_count = last_member_query_count;
-
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
 }
 
 DEFUN (interface_no_ip_igmp_last_member_query_count,
@@ -8161,21 +8476,17 @@ DEFUN (interface_no_ip_igmp_last_member_query_count,
        IFACE_IGMP_STR
        IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR)
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
+       char default_robustness[2];
 
-       if (!pim_ifp)
-               return CMD_SUCCESS;
+       snprintf(default_robustness, sizeof(default_robustness), "%d",
+                IGMP_DEFAULT_ROBUSTNESS_VARIABLE);
 
-       pim_ifp->igmp_last_member_query_count =
-               IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
+       nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_MODIFY,
+                             default_robustness);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
 }
 
-#define IGMP_LAST_MEMBER_QUERY_INTERVAL_MIN (1)
-#define IGMP_LAST_MEMBER_QUERY_INTERVAL_MAX (255)
-
 DEFUN (interface_ip_igmp_last_member_query_interval,
        interface_ip_igmp_last_member_query_interval_cmd,
        "ip igmp last-member-query-interval (1-255)",
@@ -8184,23 +8495,24 @@ DEFUN (interface_ip_igmp_last_member_query_interval,
        IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR
        "Last member query interval in deciseconds\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
-       int last_member_query_interval;
-       int ret;
+       const struct lyd_node *pim_enable_dnode;
 
-       if (!pim_ifp) {
-               ret = pim_cmd_igmp_start(vty, ifp);
-               if (ret != CMD_SUCCESS)
-                       return ret;
-               pim_ifp = ifp->info;
+       pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                         "%s/frr-pim:pim/pim-enable",
+                                         VTY_CURR_XPATH);
+       if (!pim_enable_dnode) {
+               nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
+                                     "true");
+       } else {
+               if (!yang_dnode_get_bool(pim_enable_dnode, "."))
+                       nb_cli_enqueue_change(vty, "./igmp-enable",
+                                             NB_OP_MODIFY, "true");
        }
 
-       last_member_query_interval = atoi(argv[3]->arg);
-       pim_ifp->igmp_specific_query_max_response_time_dsec
-               = last_member_query_interval;
+       nb_cli_enqueue_change(vty, "./last-member-query-interval", NB_OP_MODIFY,
+                             argv[3]->arg);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
 }
 
 DEFUN (interface_no_ip_igmp_last_member_query_interval,
@@ -8211,16 +8523,16 @@ DEFUN (interface_no_ip_igmp_last_member_query_interval,
        IFACE_IGMP_STR
        IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR)
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
+       char default_last_member_query_count[4];
 
-       if (!pim_ifp)
-               return CMD_SUCCESS;
+       snprintf(default_last_member_query_count,
+                sizeof(default_last_member_query_count),
+                "%d", IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC);
 
-       pim_ifp->igmp_specific_query_max_response_time_dsec =
-               IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
+       nb_cli_enqueue_change(vty, "./last-member-query-interval", NB_OP_MODIFY,
+                             default_last_member_query_count);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
 }
 
 DEFUN (interface_ip_pim_drprio,
@@ -8231,26 +8543,12 @@ DEFUN (interface_ip_pim_drprio,
        "Set the Designated Router Election Priority\n"
        "Value of the new DR Priority\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
        int idx_number = 3;
-       struct pim_interface *pim_ifp = ifp->info;
-       uint32_t old_dr_prio;
-
-       if (!pim_ifp) {
-               vty_out(vty, "Please enable PIM on interface, first\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
 
-       old_dr_prio = pim_ifp->pim_dr_priority;
+       nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY,
+                             argv[idx_number]->arg);
 
-       pim_ifp->pim_dr_priority = strtol(argv[idx_number]->arg, NULL, 10);
-
-       if (old_dr_prio != pim_ifp->pim_dr_priority) {
-               pim_if_dr_election(ifp);
-               pim_hello_restart_now(ifp);
-       }
-
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
 DEFUN (interface_no_ip_pim_drprio,
@@ -8262,31 +8560,25 @@ DEFUN (interface_no_ip_pim_drprio,
        "Revert the Designated Router Priority to default\n"
        "Old Value of the Priority\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
+       char default_priority[10];
 
-       if (!pim_ifp) {
-               vty_out(vty, "Pim not enabled on this interface\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       snprintf(default_priority, sizeof(default_priority), "%d",
+                PIM_DEFAULT_DR_PRIORITY);
 
-       if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) {
-               pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
-               pim_if_dr_election(ifp);
-               pim_hello_restart_now(ifp);
-       }
+       nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY,
+                             default_priority);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
 DEFPY_HIDDEN (interface_ip_igmp_query_generate,
-       interface_ip_igmp_query_generate_cmd,
-       "ip igmp generate-query-once [version (2-3)]",
-       IP_STR
-       IFACE_IGMP_STR
-       "Generate igmp general query once\n"
-       "IGMP version\n"
-       "IGMP version number\n")
+             interface_ip_igmp_query_generate_cmd,
+             "ip igmp generate-query-once [version (2-3)]",
+             IP_STR
+             IFACE_IGMP_STR
+             "Generate igmp general query once\n"
+             "IGMP version\n"
+             "IGMP version number\n")
 {
        VTY_DECLVAR_CONTEXT(interface, ifp);
        int igmp_version = 2;
@@ -8305,30 +8597,6 @@ DEFPY_HIDDEN (interface_ip_igmp_query_generate,
        return CMD_SUCCESS;
 }
 
-static int pim_cmd_interface_add(struct vty *vty, struct interface *ifp)
-{
-       struct pim_interface *pim_ifp = ifp->info;
-       struct pim_instance *pim;
-
-       if (!pim_ifp) {
-               pim = pim_get_pim_instance(ifp->vrf_id);
-               /* Limiting mcast interfaces to number of VIFs */
-               if (pim->mcast_if_count == MAXVIFS) {
-                       vty_out(vty, "Max multicast interfaces(%d) reached.",
-                               MAXVIFS);
-                       return 0;
-               }
-               pim_ifp = pim_if_new(ifp, false, true, false, false);
-       } else
-               PIM_IF_DO_PIM(pim_ifp->options);
-
-       pim_if_addr_add_all(ifp);
-       pim_if_membership_refresh(ifp);
-
-       pim_if_create_pimreg(pim_ifp->pim);
-       return 1;
-}
-
 DEFPY_HIDDEN (pim_test_sg_keepalive,
              pim_test_sg_keepalive_cmd,
              "test pim [vrf NAME$name] keepalive-reset A.B.C.D$source A.B.C.D$group",
@@ -8387,77 +8655,52 @@ DEFPY (interface_ip_pim_activeactive,
        PIM_STR
        "Mark interface as Active-Active for MLAG operations, Hidden because not finished yet\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp;
-
-       if (!no && !pim_cmd_interface_add(vty, ifp)) {
-               vty_out(vty,
-                       "Could not enable PIM SM active-active on interface %s\n",
-                       ifp->name);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-
-       if (PIM_DEBUG_MLAG)
-               zlog_debug("%sConfiguring PIM active-active on Interface: %s",
-                          no ? "Un-" : " ", ifp->name);
-
-       pim_ifp = ifp->info;
        if (no)
-               pim_if_unconfigure_mlag_dualactive(pim_ifp);
-       else
-               pim_if_configure_mlag_dualactive(pim_ifp);
-
-       return CMD_SUCCESS;
-}
-
-DEFUN_HIDDEN (interface_ip_pim_ssm,
-       interface_ip_pim_ssm_cmd,
-       "ip pim ssm",
-       IP_STR
-       PIM_STR
-       IFACE_PIM_STR)
-{
-       VTY_DECLVAR_CONTEXT(interface, ifp);
+               nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY,
+                                     "false");
+       else {
+               nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+                                     "true");
 
-       if (!pim_cmd_interface_add(vty, ifp)) {
-               vty_out(vty, "Could not enable PIM SM on interface %s\n",
-                       ifp->name);
-               return CMD_WARNING_CONFIG_FAILED;
+               nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY,
+                                     "true");
        }
 
-       vty_out(vty,
-               "WARN: Enabled PIM SM on interface; configure PIM SSM range if needed\n");
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
-static int interface_ip_pim_helper(struct vty *vty)
+DEFUN_HIDDEN (interface_ip_pim_ssm,
+             interface_ip_pim_ssm_cmd,
+             "ip pim ssm",
+             IP_STR
+             PIM_STR
+             IFACE_PIM_STR)
 {
-       struct pim_interface *pim_ifp;
+       int ret;
 
-       VTY_DECLVAR_CONTEXT(interface, ifp);
+       nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true");
 
-       if (!pim_cmd_interface_add(vty, ifp)) {
-               vty_out(vty, "Could not enable PIM SM on interface %s\n",
-                       ifp->name);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       ret = nb_cli_apply_changes(vty, "./frr-pim:pim");
 
-       pim_ifp = ifp->info;
+       if (ret != NB_OK)
+               return ret;
 
-       pim_if_create_pimreg(pim_ifp->pim);
+       vty_out(vty,
+               "WARN: Enabled PIM SM on interface; configure PIM SSM range if needed\n");
 
-       return CMD_SUCCESS;
+       return NB_OK;
 }
 
 DEFUN_HIDDEN (interface_ip_pim_sm,
-       interface_ip_pim_sm_cmd,
-       "ip pim sm",
-       IP_STR
-       PIM_STR
-       IFACE_PIM_SM_STR)
+             interface_ip_pim_sm_cmd,
+             "ip pim sm",
+             IP_STR
+             PIM_STR
+             IFACE_PIM_SM_STR)
 {
-       return interface_ip_pim_helper(vty);
+       nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true");
+
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
 DEFUN (interface_ip_pim,
@@ -8466,65 +8709,73 @@ DEFUN (interface_ip_pim,
        IP_STR
        PIM_STR)
 {
-       return interface_ip_pim_helper(vty);
+       nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true");
+
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
-static int pim_cmd_interface_delete(struct interface *ifp)
+DEFUN_HIDDEN (interface_no_ip_pim_ssm,
+             interface_no_ip_pim_ssm_cmd,
+             "no ip pim ssm",
+             NO_STR
+             IP_STR
+             PIM_STR
+             IFACE_PIM_STR)
 {
-       struct pim_interface *pim_ifp = ifp->info;
-
-       if (!pim_ifp)
-               return 1;
+       const struct lyd_node *igmp_enable_dnode;
+       char igmp_if_xpath[XPATH_MAXLEN + 20];
 
-       PIM_IF_DONT_PIM(pim_ifp->options);
+       snprintf(igmp_if_xpath, sizeof(igmp_if_xpath),
+                "%s/frr-igmp:igmp", VTY_CURR_XPATH);
+       igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                          "%s/igmp-enable", igmp_if_xpath);
 
-       pim_if_membership_clear(ifp);
-
-       /*
-         pim_sock_delete() removes all neighbors from
-         pim_ifp->pim_neighbor_list.
-        */
-       pim_sock_delete(ifp, "pim unconfigured on interface");
-
-       if (!PIM_IF_TEST_IGMP(pim_ifp->options)) {
-               pim_if_addr_del_all(ifp);
-               pim_if_delete(ifp);
+       if (!igmp_enable_dnode) {
+               nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL);
+               nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+       } else {
+               if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) {
+                       nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY,
+                                             NULL);
+                       nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+               } else
+                       nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+                                             "false");
        }
 
-       return 1;
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
-static int interface_no_ip_pim_helper(struct vty *vty)
+DEFUN_HIDDEN (interface_no_ip_pim_sm,
+             interface_no_ip_pim_sm_cmd,
+             "no ip pim sm",
+             NO_STR
+             IP_STR
+             PIM_STR
+             IFACE_PIM_SM_STR)
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       if (!pim_cmd_interface_delete(ifp)) {
-               vty_out(vty, "Unable to delete interface information\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       const struct lyd_node *igmp_enable_dnode;
+       char igmp_if_xpath[XPATH_MAXLEN + 20];
 
-       return CMD_SUCCESS;
-}
+       snprintf(igmp_if_xpath, sizeof(igmp_if_xpath),
+                "%s/frr-igmp:igmp", VTY_CURR_XPATH);
+       igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                          "%s/igmp-enable", igmp_if_xpath);
 
-DEFUN_HIDDEN (interface_no_ip_pim_ssm,
-       interface_no_ip_pim_ssm_cmd,
-       "no ip pim ssm",
-       NO_STR
-       IP_STR
-       PIM_STR
-       IFACE_PIM_STR)
-{
-       return interface_no_ip_pim_helper(vty);
-}
+       if (!igmp_enable_dnode) {
+               nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL);
+               nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+       } else {
+               if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) {
+                       nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY,
+                                             NULL);
+                       nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+               } else
+                       nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+                                             "false");
+       }
 
-DEFUN_HIDDEN (interface_no_ip_pim_sm,
-       interface_no_ip_pim_sm_cmd,
-       "no ip pim sm",
-       NO_STR
-       IP_STR
-       PIM_STR
-       IFACE_PIM_SM_STR)
-{
-       return interface_no_ip_pim_helper(vty);
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
 DEFUN (interface_no_ip_pim,
@@ -8534,7 +8785,28 @@ DEFUN (interface_no_ip_pim,
        IP_STR
        PIM_STR)
 {
-       return interface_no_ip_pim_helper(vty);
+       const struct lyd_node *igmp_enable_dnode;
+       char igmp_if_xpath[XPATH_MAXLEN + 20];
+
+       snprintf(igmp_if_xpath, sizeof(igmp_if_xpath),
+                "%s/frr-igmp:igmp", VTY_CURR_XPATH);
+       igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                          "%s/igmp-enable", igmp_if_xpath);
+
+       if (!igmp_enable_dnode) {
+               nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL);
+               nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+       } else {
+               if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) {
+                       nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY,
+                                             NULL);
+                       nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+               } else
+                       nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+                                             "false");
+       }
+
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
 /* boundaries */
@@ -8547,22 +8819,13 @@ DEFUN(interface_ip_pim_boundary_oil,
       "Filter OIL by group using prefix list\n"
       "Prefix list to filter OIL with\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, iif);
-       struct pim_interface *pim_ifp;
-       int idx = 0;
-
-       argv_find(argv, argc, "WORD", &idx);
+       nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_MODIFY,
+                             argv[4]->arg);
 
-       PIM_GET_PIM_INTERFACE(pim_ifp, iif);
+       return nb_cli_apply_changes(vty,
+                                   "./frr-pim:pim/address-family[address-family='%s']",
+                                   "frr-routing:ipv4");
 
-       if (pim_ifp->boundary_oil_plist)
-               XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
-
-       pim_ifp->boundary_oil_plist =
-               XSTRDUP(MTYPE_PIM_INTERFACE, argv[idx]->arg);
-
-       /* Interface will be pruned from OIL on next Join */
-       return CMD_SUCCESS;
 }
 
 DEFUN(interface_no_ip_pim_boundary_oil,
@@ -8575,18 +8838,12 @@ DEFUN(interface_no_ip_pim_boundary_oil,
       "Filter OIL by group using prefix list\n"
       "Prefix list to filter OIL with\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, iif);
-       struct pim_interface *pim_ifp;
-       int idx = 0;
-
-       argv_find(argv, argc, "WORD", &idx);
-
-       PIM_GET_PIM_INTERFACE(pim_ifp, iif);
-
-       if (pim_ifp->boundary_oil_plist)
-               XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
+       nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_DESTROY,
+                             NULL);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty,
+                                   "./frr-pim:pim/address-family[address-family='%s']",
+                                   "frr-routing:ipv4");
 }
 
 DEFUN (interface_ip_mroute,
@@ -8598,56 +8855,22 @@ DEFUN (interface_ip_mroute,
        "Group address\n"
        "Source address\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, iif);
-       struct pim_interface *pim_ifp;
-       struct pim_instance *pim;
        int idx_interface = 2;
        int idx_ipv4 = 3;
-       struct interface *oif;
-       const char *oifname;
-       const char *grp_str;
-       struct in_addr grp_addr;
-       const char *src_str;
-       struct in_addr src_addr;
-       int result;
-
-       PIM_GET_PIM_INTERFACE(pim_ifp, iif);
-       pim = pim_ifp->pim;
-
-       oifname = argv[idx_interface]->arg;
-       oif = if_lookup_by_name(oifname, pim->vrf_id);
-       if (!oif) {
-               vty_out(vty, "No such interface name %s\n", oifname);
-               return CMD_WARNING;
-       }
+       const char *source_str;
 
-       grp_str = argv[idx_ipv4]->arg;
-       result = inet_pton(AF_INET, grp_str, &grp_addr);
-       if (result <= 0) {
-               vty_out(vty, "Bad group address %s: errno=%d: %s\n", grp_str,
-                       errno, safe_strerror(errno));
-               return CMD_WARNING;
-       }
+       if (argc == (idx_ipv4 + 1))
+               source_str = "0.0.0.0";
+       else
+               source_str = argv[idx_ipv4 + 1]->arg;
 
-        if (argc == (idx_ipv4 + 1)) {
-                src_addr.s_addr = INADDR_ANY;
-        }
-        else {
-                src_str = argv[idx_ipv4 + 1]->arg;
-                result = inet_pton(AF_INET, src_str, &src_addr);
-                if (result <= 0) {
-                        vty_out(vty, "Bad source address %s: errno=%d: %s\n", src_str,
-                                errno, safe_strerror(errno));
-                        return CMD_WARNING;
-                }
-        }
-
-       if (pim_static_add(pim, iif, oif, grp_addr, src_addr)) {
-               vty_out(vty, "Failed to add static mroute\n");
-               return CMD_WARNING;
-       }
+       nb_cli_enqueue_change(vty, "./oif", NB_OP_MODIFY,
+                             argv[idx_interface]->arg);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty,
+                                   "./frr-pim:pim/address-family[address-family='%s']/mroute[source-addr='%s'][group-addr='%s']",
+                                   "frr-routing:ipv4", source_str,
+                                   argv[idx_ipv4]->arg);
 }
 
 DEFUN (interface_no_ip_mroute,
@@ -8660,56 +8883,20 @@ DEFUN (interface_no_ip_mroute,
        "Group Address\n"
        "Source Address\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, iif);
-       struct pim_interface *pim_ifp;
-       struct pim_instance *pim;
-       int idx_interface = 3;
        int idx_ipv4 = 4;
-       struct interface *oif;
-       const char *oifname;
-       const char *grp_str;
-       struct in_addr grp_addr;
-       const char *src_str;
-       struct in_addr src_addr;
-       int result;
-
-       PIM_GET_PIM_INTERFACE(pim_ifp, iif);
-       pim = pim_ifp->pim;
-
-       oifname = argv[idx_interface]->arg;
-       oif = if_lookup_by_name(oifname, pim->vrf_id);
-       if (!oif) {
-               vty_out(vty, "No such interface name %s\n", oifname);
-               return CMD_WARNING;
-       }
+       const char *source_str;
 
-       grp_str = argv[idx_ipv4]->arg;
-       result = inet_pton(AF_INET, grp_str, &grp_addr);
-       if (result <= 0) {
-               vty_out(vty, "Bad group address %s: errno=%d: %s\n", grp_str,
-                       errno, safe_strerror(errno));
-               return CMD_WARNING;
-       }
+       if (argc == (idx_ipv4 + 1))
+               source_str = "0.0.0.0";
+       else
+               source_str = argv[idx_ipv4 + 1]->arg;
 
-        if (argc == (idx_ipv4 + 1)) {
-                src_addr.s_addr = INADDR_ANY;
-        }
-        else {
-                src_str = argv[idx_ipv4 + 1]->arg;
-                result = inet_pton(AF_INET, src_str, &src_addr);
-                if (result <= 0) {
-                        vty_out(vty, "Bad source address %s: errno=%d: %s\n", src_str,
-                                errno, safe_strerror(errno));
-                        return CMD_WARNING;
-                }
-        }
-
-       if (pim_static_del(pim, iif, oif, grp_addr, src_addr)) {
-               vty_out(vty, "Failed to remove static mroute\n");
-               return CMD_WARNING;
-       }
+       nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty,
+                                   "./frr-pim:pim/address-family[address-family='%s']/mroute[source-addr='%s'][group-addr='%s']",
+                                   "frr-routing:ipv4", source_str,
+                                   argv[idx_ipv4]->arg);
 }
 
 DEFUN (interface_ip_pim_hello,
@@ -8721,28 +8908,30 @@ DEFUN (interface_ip_pim_hello,
        IFACE_PIM_HELLO_TIME_STR
        IFACE_PIM_HELLO_HOLD_STR)
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
        int idx_time = 3;
        int idx_hold = 4;
-       struct pim_interface *pim_ifp = ifp->info;
-
-       if (!pim_ifp) {
-               if (!pim_cmd_interface_add(vty, ifp)) {
-                       vty_out(vty,
-                               "Could not enable PIM SM on interface %s\n",
-                               ifp->name);
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
+       const struct lyd_node *igmp_enable_dnode;
+
+       igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                          "%s/frr-igmp:igmp/igmp-enable",
+                                          VTY_CURR_XPATH);
+       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");
        }
 
-       pim_ifp = ifp->info;
-       pim_ifp->pim_hello_period = strtol(argv[idx_time]->arg, NULL, 10);
+       nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY,
+                             argv[idx_time]->arg);
 
        if (argc == idx_hold + 1)
-               pim_ifp->pim_default_holdtime =
-                       strtol(argv[idx_hold]->arg, NULL, 10);
+               nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_MODIFY,
+                                     argv[idx_hold]->arg);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
 DEFUN (interface_no_ip_pim_hello,
@@ -8755,18 +8944,16 @@ DEFUN (interface_no_ip_pim_hello,
        IFACE_PIM_HELLO_TIME_STR
        IFACE_PIM_HELLO_HOLD_STR)
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
+       char hello_default_timer[3];
 
-       if (!pim_ifp) {
-               vty_out(vty, "Pim not enabled on this interface\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       snprintf(hello_default_timer, sizeof(hello_default_timer), "%d",
+                PIM_DEFAULT_HELLO_PERIOD);
 
-       pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
-       pim_ifp->pim_default_holdtime = -1;
+       nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY,
+                             hello_default_timer);
+       nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_DESTROY, NULL);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
 DEFUN (debug_igmp,
@@ -9394,47 +9581,13 @@ DEFUN_NOSH (show_debugging_pim,
            "show debugging [pim]",
            SHOW_STR
            DEBUG_STR
-           PIM_STR)
-{
-       vty_out(vty, "PIM debugging status\n");
-
-       pim_debug_config_write(vty);
-
-       return CMD_SUCCESS;
-}
-
-static int interface_pim_use_src_cmd_worker(struct vty *vty, const char *source)
-{
-       int result;
-       struct in_addr source_addr;
-       int ret = CMD_SUCCESS;
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-
-       result = inet_pton(AF_INET, source, &source_addr);
-       if (result <= 0) {
-               vty_out(vty, "%% Bad source address %s: errno=%d: %s\n", source,
-                       errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+           PIM_STR)
+{
+       vty_out(vty, "PIM debugging status\n");
 
-       result = pim_update_source_set(ifp, source_addr);
-       switch (result) {
-       case PIM_SUCCESS:
-               break;
-       case PIM_IFACE_NOT_FOUND:
-               ret = CMD_WARNING_CONFIG_FAILED;
-               vty_out(vty, "Pim not enabled on this interface\n");
-               break;
-       case PIM_UPDATE_SOURCE_DUP:
-               ret = CMD_WARNING;
-               vty_out(vty, "%% Source already set to %s\n", source);
-               break;
-       default:
-               ret = CMD_WARNING_CONFIG_FAILED;
-               vty_out(vty, "%% Source set failed\n");
-       }
+       pim_debug_config_write(vty);
 
-       return ret;
+       return CMD_SUCCESS;
 }
 
 DEFUN (interface_pim_use_source,
@@ -9445,7 +9598,11 @@ DEFUN (interface_pim_use_source,
        "Configure primary IP address\n"
        "source ip address\n")
 {
-       return interface_pim_use_src_cmd_worker(vty, argv[3]->arg);
+       nb_cli_enqueue_change(vty, "./use-source", NB_OP_MODIFY, argv[3]->arg);
+
+       return nb_cli_apply_changes(vty,
+                                   "./frr-pim:pim/address-family[address-family='%s']",
+                                   "frr-routing:ipv4");
 }
 
 DEFUN (interface_no_pim_use_source,
@@ -9457,7 +9614,11 @@ DEFUN (interface_no_pim_use_source,
        "Delete source IP address\n"
        "source ip address\n")
 {
-       return interface_pim_use_src_cmd_worker(vty, "0.0.0.0");
+       nb_cli_enqueue_change(vty, "./use-source", NB_OP_MODIFY, "0.0.0.0");
+
+       return nb_cli_apply_changes(vty,
+                                   "./frr-pim:pim/address-family[address-family='%s']",
+                                   "frr-routing:ipv4");
 }
 
 DEFUN (ip_pim_bfd,
@@ -9467,27 +9628,50 @@ DEFUN (ip_pim_bfd,
        PIM_STR
        "Enables BFD support\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
        struct bfd_info *bfd_info = NULL;
-
-       if (!pim_ifp) {
-               if (!pim_cmd_interface_add(vty, ifp)) {
-                       vty_out(vty,
-                               "Could not enable PIM SM on interface %s\n",
-                               ifp->name);
-                       return CMD_WARNING;
-               }
+       char default_rx_interval[5];
+       char default_tx_interval[5];
+       char default_detect_mult[3];
+       const struct lyd_node *igmp_enable_dnode;
+       char bfd_xpath[XPATH_MAXLEN + 20];
+
+       igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                          "%s/frr-igmp:igmp/igmp-enable",
+                                          VTY_CURR_XPATH);
+       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");
        }
-       pim_ifp = ifp->info;
 
-       bfd_info = pim_ifp->bfd_info;
+       snprintf(default_rx_interval, sizeof(default_rx_interval), "%d",
+                BFD_DEF_MIN_RX);
+       snprintf(default_tx_interval, sizeof(default_tx_interval), "%d",
+                BFD_DEF_MIN_TX);
+       snprintf(default_detect_mult, sizeof(default_detect_mult), "%d",
+                BFD_DEF_DETECT_MULT);
 
-       if (!bfd_info || !CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
-               pim_bfd_if_param_set(ifp, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
-                                    BFD_DEF_DETECT_MULT, 1);
+       snprintf(bfd_xpath, sizeof(bfd_xpath), "%s/frr-pim:pim/bfd",
+                VTY_CURR_XPATH);
+       bfd_info = nb_running_get_entry(NULL, bfd_xpath, false);
 
-       return CMD_SUCCESS;
+       if (!bfd_info ||
+           !CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) {
+               nb_cli_enqueue_change(vty, "./bfd/min-rx-interval",
+                                     NB_OP_MODIFY, default_rx_interval);
+               nb_cli_enqueue_change(vty, "./bfd/min-tx-interval",
+                                     NB_OP_MODIFY, default_tx_interval);
+               nb_cli_enqueue_change(vty, "./bfd/detect_mult",
+                                     NB_OP_MODIFY,
+                                     default_detect_mult);
+
+               return nb_cli_apply_changes(vty, "./frr-pim:pim");
+       }
+
+       return NB_OK;
 }
 
 DEFUN (no_ip_pim_bfd,
@@ -9498,20 +9682,9 @@ DEFUN (no_ip_pim_bfd,
        PIM_STR
        "Disables BFD support\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
+       nb_cli_enqueue_change(vty, "./bfd", NB_OP_DESTROY, NULL);
 
-       if (!pim_ifp) {
-               vty_out(vty, "Pim not enabled on this interface\n");
-               return CMD_WARNING;
-       }
-
-       if (pim_ifp->bfd_info) {
-               pim_bfd_reg_dereg_all_nbr(ifp, ZEBRA_BFD_DEST_DEREGISTER);
-               bfd_info_free(&(pim_ifp->bfd_info));
-       }
-
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
 DEFUN (ip_pim_bsm,
@@ -9521,22 +9694,23 @@ DEFUN (ip_pim_bsm,
        PIM_STR
        "Enables BSM support on the interface\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
+       const struct lyd_node *igmp_enable_dnode;
 
-       if (!pim_ifp) {
-               if (!pim_cmd_interface_add(vty, ifp)) {
-                       vty_out(vty,
-                               "Could not enable PIM SM on interface %s\n",
-                               ifp->name);
-                       return CMD_WARNING;
-               }
+       igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                          "%s/frr-igmp:igmp/igmp-enable",
+                                          VTY_CURR_XPATH);
+       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");
        }
 
-       pim_ifp = ifp->info;
-       pim_ifp->bsm_enable = true;
+       nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "true");
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
 DEFUN (no_ip_pim_bsm,
@@ -9547,17 +9721,9 @@ DEFUN (no_ip_pim_bsm,
        PIM_STR
        "Disables BSM support\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
-
-       if (!pim_ifp) {
-               vty_out(vty, "Pim not enabled on this interface\n");
-               return CMD_WARNING;
-       }
-
-       pim_ifp->bsm_enable = false;
+       nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "false");
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
 DEFUN (ip_pim_ucast_bsm,
@@ -9567,22 +9733,23 @@ DEFUN (ip_pim_ucast_bsm,
        PIM_STR
        "Accept/Send unicast BSM on the interface\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
+       const struct lyd_node *igmp_enable_dnode;
 
-       if (!pim_ifp) {
-               if (!pim_cmd_interface_add(vty, ifp)) {
-                       vty_out(vty,
-                               "Could not enable PIM SM on interface %s\n",
-                               ifp->name);
-                       return CMD_WARNING;
-               }
+       igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                          "%s/frr-igmp:igmp/igmp-enable",
+                                          VTY_CURR_XPATH);
+       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");
        }
 
-       pim_ifp = ifp->info;
-       pim_ifp->ucast_bsm_accept = true;
+       nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "true");
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
 DEFUN (no_ip_pim_ucast_bsm,
@@ -9593,44 +9760,35 @@ DEFUN (no_ip_pim_ucast_bsm,
        PIM_STR
        "Block send/receive unicast BSM on this interface\n")
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct pim_interface *pim_ifp = ifp->info;
-
-       if (!pim_ifp) {
-               vty_out(vty, "Pim not enabled on this interface\n");
-               return CMD_WARNING;
-       }
+       nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "false");
 
-       pim_ifp->ucast_bsm_accept = false;
-
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
 #if HAVE_BFDD > 0
 DEFUN_HIDDEN(
-       ip_pim_bfd_param,
-       ip_pim_bfd_param_cmd,
-       "ip pim bfd (2-255) (50-60000) (50-60000)",
-       IP_STR
-       PIM_STR
-       "Enables BFD support\n"
-       "Detect Multiplier\n"
-       "Required min receive interval\n"
-       "Desired min transmit interval\n")
+       ip_pim_bfd_param,
+       ip_pim_bfd_param_cmd,
+       "ip pim bfd (2-255) (50-60000) (50-60000)",
+       IP_STR
+       PIM_STR
+       "Enables BFD support\n"
+       "Detect Multiplier\n"
+       "Required min receive interval\n"
+       "Desired min transmit interval\n")
 #else
-DEFUN(
-       ip_pim_bfd_param,
-       ip_pim_bfd_param_cmd,
-       "ip pim bfd (2-255) (50-60000) (50-60000)",
-       IP_STR
-       PIM_STR
-       "Enables BFD support\n"
-       "Detect Multiplier\n"
-       "Required min receive interval\n"
-       "Desired min transmit interval\n")
+       DEFUN(
+               ip_pim_bfd_param,
+               ip_pim_bfd_param_cmd,
+               "ip pim bfd (2-255) (50-60000) (50-60000)",
+               IP_STR
+               PIM_STR
+               "Enables BFD support\n"
+               "Detect Multiplier\n"
+               "Required min receive interval\n"
+               "Desired min transmit interval\n")
 #endif /* HAVE_BFDD */
 {
-       VTY_DECLVAR_CONTEXT(interface, ifp);
        int idx_number = 3;
        int idx_number_2 = 4;
        int idx_number_3 = 5;
@@ -9638,26 +9796,35 @@ DEFUN(
        uint32_t tx_val;
        uint8_t dm_val;
        int ret;
-       struct pim_interface *pim_ifp = ifp->info;
-
-       if (!pim_ifp) {
-               if (!pim_cmd_interface_add(vty, ifp)) {
-                       vty_out(vty,
-                               "Could not enable PIM SM on interface %s\n",
-                               ifp->name);
-                       return CMD_WARNING;
-               }
-       }
+       const struct lyd_node *igmp_enable_dnode;
 
-       if ((ret = bfd_validate_param(
-                    vty, argv[idx_number]->arg, argv[idx_number_2]->arg,
-                    argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val))
+       if ((ret = bfd_validate_param(vty, argv[idx_number]->arg,
+                                     argv[idx_number_2]->arg,
+                                     argv[idx_number_3]->arg, &dm_val, &rx_val,
+                                     &tx_val))
            != CMD_SUCCESS)
                return ret;
 
-       pim_bfd_if_param_set(ifp, rx_val, tx_val, dm_val, 0);
+       igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                          "%s/frr-igmp:igmp/igmp-enable",
+                                          VTY_CURR_XPATH);
+       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, "./bfd/min-rx-interval", NB_OP_MODIFY,
+                             argv[idx_number_2]->arg);
+       nb_cli_enqueue_change(vty, "./bfd/min-tx-interval", NB_OP_MODIFY,
+                             argv[idx_number_3]->arg);
+       nb_cli_enqueue_change(vty, "./bfd/detect_mult", NB_OP_MODIFY,
+                             argv[idx_number]->arg);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, "./frr-pim:pim");
 }
 
 #if HAVE_BFDD == 0
@@ -9669,92 +9836,47 @@ ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd,
       "Desired min transmit interval\n")
 #endif /* !HAVE_BFDD */
 
-static int ip_msdp_peer_cmd_worker(struct pim_instance *pim, struct vty *vty,
-                                  const char *peer, const char *local)
-{
-       enum pim_msdp_err result;
-       struct in_addr peer_addr;
-       struct in_addr local_addr;
-       int ret = CMD_SUCCESS;
-
-       result = inet_pton(AF_INET, peer, &peer_addr);
-       if (result <= 0) {
-               vty_out(vty, "%% Bad peer address %s: errno=%d: %s\n", peer,
-                       errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       result = inet_pton(AF_INET, local, &local_addr);
-       if (result <= 0) {
-               vty_out(vty, "%% Bad source address %s: errno=%d: %s\n", local,
-                       errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       result = pim_msdp_peer_add(pim, peer_addr, local_addr, "default",
-                                  NULL /* mp_p */);
-       switch (result) {
-       case PIM_MSDP_ERR_NONE:
-               break;
-       case PIM_MSDP_ERR_OOM:
-               ret = CMD_WARNING_CONFIG_FAILED;
-               vty_out(vty, "%% Out of memory\n");
-               break;
-       case PIM_MSDP_ERR_PEER_EXISTS:
-               ret = CMD_WARNING;
-               vty_out(vty, "%% Peer exists\n");
-               break;
-       case PIM_MSDP_ERR_MAX_MESH_GROUPS:
-               ret = CMD_WARNING_CONFIG_FAILED;
-               vty_out(vty, "%% Only one mesh-group allowed currently\n");
-               break;
-       default:
-               ret = CMD_WARNING_CONFIG_FAILED;
-               vty_out(vty, "%% peer add failed\n");
-       }
-
-       return ret;
-}
-
-DEFUN (ip_msdp_peer,
-       ip_msdp_peer_cmd,
-       "ip msdp peer A.B.C.D source A.B.C.D",
-       IP_STR
-       CFG_MSDP_STR
-       "Configure MSDP peer\n"
-       "peer ip address\n"
-       "Source address for TCP connection\n"
-       "local ip address\n")
-{
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       return ip_msdp_peer_cmd_worker(pim, vty, argv[3]->arg, argv[5]->arg);
-}
-
-static int ip_no_msdp_peer_cmd_worker(struct pim_instance *pim, struct vty *vty,
-                                     const char *peer)
-{
-       enum pim_msdp_err result;
-       struct in_addr peer_addr;
+       DEFUN (ip_msdp_peer,
+              ip_msdp_peer_cmd,
+              "ip msdp peer A.B.C.D source A.B.C.D",
+              IP_STR
+              CFG_MSDP_STR
+              "Configure MSDP peer\n"
+              "peer ip address\n"
+              "Source address for TCP connection\n"
+              "local ip address\n")
+{
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char temp_xpath[XPATH_MAXLEN];
+       char msdp_peer_source_xpath[XPATH_MAXLEN];
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
 
-       result = inet_pton(AF_INET, peer, &peer_addr);
-       if (result <= 0) {
-               vty_out(vty, "%% Bad peer address %s: errno=%d: %s\n", peer,
-                       errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       snprintf(temp_xpath, sizeof(temp_xpath),
+                "/msdp-peer[peer-ip='%s']/source-ip",
+                argv[3]->arg);
+       strlcat(msdp_peer_source_xpath, temp_xpath,
+               sizeof(msdp_peer_source_xpath));
 
-       result = pim_msdp_peer_del(pim, peer_addr);
-       switch (result) {
-       case PIM_MSDP_ERR_NONE:
-               break;
-       case PIM_MSDP_ERR_NO_PEER:
-               vty_out(vty, "%% Peer does not exist\n");
-               break;
-       default:
-               vty_out(vty, "%% peer del failed\n");
-       }
+       nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY,
+                             argv[5]->arg);
 
-       return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_msdp_peer,
@@ -9766,47 +9888,36 @@ DEFUN (no_ip_msdp_peer,
        "Delete MSDP peer\n"
        "peer ip address\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       return ip_no_msdp_peer_cmd_worker(pim, vty, argv[4]->arg);
-}
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char msdp_peer_xpath[XPATH_MAXLEN];
+       char temp_xpath[XPATH_MAXLEN];
 
-static int ip_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
-                                               struct vty *vty, const char *mg,
-                                               const char *mbr)
-{
-       enum pim_msdp_err result;
-       struct in_addr mbr_ip;
-       int ret = CMD_SUCCESS;
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
 
-       result = inet_pton(AF_INET, mbr, &mbr_ip);
-       if (result <= 0) {
-               vty_out(vty, "%% Bad member address %s: errno=%d: %s\n", mbr,
-                       errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       snprintf(temp_xpath, sizeof(temp_xpath),
+                "/msdp-peer[peer-ip='%s']",
+                argv[4]->arg);
 
-       result = pim_msdp_mg_mbr_add(pim, mg, mbr_ip);
-       switch (result) {
-       case PIM_MSDP_ERR_NONE:
-               break;
-       case PIM_MSDP_ERR_OOM:
-               ret = CMD_WARNING_CONFIG_FAILED;
-               vty_out(vty, "%% Out of memory\n");
-               break;
-       case PIM_MSDP_ERR_MG_MBR_EXISTS:
-               ret = CMD_WARNING;
-               vty_out(vty, "%% mesh-group member exists\n");
-               break;
-       case PIM_MSDP_ERR_MAX_MESH_GROUPS:
-               ret = CMD_WARNING_CONFIG_FAILED;
-               vty_out(vty, "%% Only one mesh-group allowed currently\n");
-               break;
-       default:
-               ret = CMD_WARNING_CONFIG_FAILED;
-               vty_out(vty, "%% member add failed\n");
-       }
+       strlcat(msdp_peer_xpath, temp_xpath, sizeof(msdp_peer_xpath));
 
-       return ret;
+       nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (ip_msdp_mesh_group_member,
@@ -9819,42 +9930,44 @@ DEFUN (ip_msdp_mesh_group_member,
        "mesh group member\n"
        "peer ip address\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       return ip_msdp_mesh_group_member_cmd_worker(pim, vty, argv[3]->arg,
-                                                   argv[5]->arg);
-}
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char msdp_mesh_group_name_xpath[XPATH_MAXLEN];
+       char msdp_mesh_group_member_xpath[XPATH_MAXLEN];
 
-static int ip_no_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
-                                                  struct vty *vty,
-                                                  const char *mg,
-                                                  const char *mbr)
-{
-       enum pim_msdp_err result;
-       struct in_addr mbr_ip;
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
 
-       result = inet_pton(AF_INET, mbr, &mbr_ip);
-       if (result <= 0) {
-               vty_out(vty, "%% Bad member address %s: errno=%d: %s\n", mbr,
-                       errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       snprintf(msdp_mesh_group_name_xpath, sizeof(msdp_mesh_group_name_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(msdp_mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
+               sizeof(msdp_mesh_group_name_xpath));
+       snprintf(msdp_mesh_group_member_xpath,
+                sizeof(msdp_mesh_group_member_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(msdp_mesh_group_member_xpath, "/msdp-mesh-group/member-ip",
+               sizeof(msdp_mesh_group_member_xpath));
 
-       result = pim_msdp_mg_mbr_del(pim, mg, mbr_ip);
-       switch (result) {
-       case PIM_MSDP_ERR_NONE:
-               break;
-       case PIM_MSDP_ERR_NO_MG:
-               vty_out(vty, "%% mesh-group does not exist\n");
-               break;
-       case PIM_MSDP_ERR_NO_MG_MBR:
-               vty_out(vty, "%% mesh-group member does not exist\n");
-               break;
-       default:
-               vty_out(vty, "%% mesh-group member del failed\n");
-       }
+       nb_cli_enqueue_change(vty, msdp_mesh_group_name_xpath, NB_OP_MODIFY,
+                             argv[3]->arg);
+       nb_cli_enqueue_change(vty, msdp_mesh_group_member_xpath, NB_OP_CREATE,
+                             argv[5]->arg);
 
-       return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, NULL);
 }
+
 DEFUN (no_ip_msdp_mesh_group_member,
        no_ip_msdp_mesh_group_member_cmd,
        "no ip msdp mesh-group WORD member A.B.C.D",
@@ -9866,42 +9979,83 @@ DEFUN (no_ip_msdp_mesh_group_member,
        "mesh group member\n"
        "peer ip address\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       return ip_no_msdp_mesh_group_member_cmd_worker(pim, vty, argv[4]->arg,
-                                                      argv[6]->arg);
-}
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char pim_af_xpath[XPATH_MAXLEN];
+       char mesh_group_xpath[XPATH_MAXLEN + 32];
+       char group_member_list_xpath[XPATH_MAXLEN + 64];
+       char group_member_xpath[XPATH_MAXLEN + 128];
+       char source_xpath[XPATH_MAXLEN + 64];
+       char mesh_group_name_xpath[XPATH_MAXLEN + 64];
+       const char *mesh_group_name;
+       const struct lyd_node *member_dnode;
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
 
-static int ip_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim,
-                                               struct vty *vty, const char *mg,
-                                               const char *src)
-{
-       enum pim_msdp_err result;
-       struct in_addr src_ip;
+       snprintf(pim_af_xpath, sizeof(pim_af_xpath), FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
 
-       result = inet_pton(AF_INET, src, &src_ip);
-       if (result <= 0) {
-               vty_out(vty, "%% Bad source address %s: errno=%d: %s\n", src,
-                       errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
+       snprintf(mesh_group_xpath, sizeof(mesh_group_xpath),
+                "%s/msdp-mesh-group", pim_af_xpath);
+
+       snprintf(group_member_list_xpath, sizeof(group_member_list_xpath),
+                "%s/msdp-mesh-group/member-ip", pim_af_xpath);
+
+       snprintf(group_member_xpath, sizeof(group_member_xpath), "%s[.='%s']",
+                group_member_list_xpath, argv[6]->arg);
+
+       snprintf(source_xpath, sizeof(source_xpath),
+                "%s/msdp-mesh-group/source-ip", pim_af_xpath);
+
+       snprintf(mesh_group_name_xpath, sizeof(mesh_group_name_xpath),
+                "%s/msdp-mesh-group/mesh-group-name", pim_af_xpath);
+
+       if (yang_dnode_exists(running_config->dnode, mesh_group_name_xpath)
+           == true) {
+               mesh_group_name = yang_dnode_get_string(running_config->dnode,
+                                                       mesh_group_name_xpath);
+               if (strcmp(mesh_group_name, argv[4]->arg)) {
+                       vty_out(vty, "%% mesh-group does not exist\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
        }
 
-       result = pim_msdp_mg_src_add(pim, mg, src_ip);
-       switch (result) {
-       case PIM_MSDP_ERR_NONE:
-               break;
-       case PIM_MSDP_ERR_OOM:
-               vty_out(vty, "%% Out of memory\n");
-               break;
-       case PIM_MSDP_ERR_MAX_MESH_GROUPS:
-               vty_out(vty, "%% Only one mesh-group allowed currently\n");
-               break;
-       default:
-               vty_out(vty, "%% source add failed\n");
+       if (yang_dnode_exists(vty->candidate_config->dnode,
+                             group_member_xpath)) {
+               if (!yang_dnode_exists(vty->candidate_config->dnode,
+                                      source_xpath)) {
+                       member_dnode = yang_dnode_get(
+                               vty->candidate_config->dnode,
+                               group_member_xpath);
+                       if (yang_is_last_list_dnode(member_dnode)) {
+                               nb_cli_enqueue_change(vty, mesh_group_xpath,
+                                                     NB_OP_DESTROY, NULL);
+                               return nb_cli_apply_changes(vty, NULL);
+                       }
+                       nb_cli_enqueue_change(vty, group_member_list_xpath,
+                                             NB_OP_DESTROY, argv[6]->arg);
+                       return nb_cli_apply_changes(vty, NULL);
+               }
+               nb_cli_enqueue_change(vty, group_member_list_xpath,
+                                     NB_OP_DESTROY, argv[6]->arg);
+               return nb_cli_apply_changes(vty, NULL);
        }
 
-       return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS;
-}
+       vty_out(vty, "%% mesh-group member does not exist\n");
 
+       return CMD_SUCCESS;
+}
 
 DEFUN (ip_msdp_mesh_group_source,
        ip_msdp_mesh_group_source_cmd,
@@ -9913,48 +10067,42 @@ DEFUN (ip_msdp_mesh_group_source,
        "mesh group local address\n"
        "source ip address for the TCP connection\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
-       return ip_msdp_mesh_group_source_cmd_worker(pim, vty, argv[3]->arg,
-                                                   argv[5]->arg);
-}
-
-static int ip_no_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim,
-                                                  struct vty *vty,
-                                                  const char *mg)
-{
-       enum pim_msdp_err result;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char msdp_mesh_source_ip_xpath[XPATH_MAXLEN];
+       char msdp_mesh_group_name_xpath[XPATH_MAXLEN];
 
-       result = pim_msdp_mg_src_del(pim, mg);
-       switch (result) {
-       case PIM_MSDP_ERR_NONE:
-               break;
-       case PIM_MSDP_ERR_NO_MG:
-               vty_out(vty, "%% mesh-group does not exist\n");
-               break;
-       default:
-               vty_out(vty, "%% mesh-group source del failed\n");
-       }
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
 
-       return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS;
-}
+       snprintf(msdp_mesh_group_name_xpath, sizeof(msdp_mesh_group_name_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(msdp_mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
+               sizeof(msdp_mesh_group_name_xpath));
 
-static int ip_no_msdp_mesh_group_cmd_worker(struct pim_instance *pim,
-                                           struct vty *vty, const char *mg)
-{
-       enum pim_msdp_err result;
+       snprintf(msdp_mesh_source_ip_xpath, sizeof(msdp_mesh_source_ip_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(msdp_mesh_source_ip_xpath, "/msdp-mesh-group/source-ip",
+               sizeof(msdp_mesh_source_ip_xpath));
 
-       result = pim_msdp_mg_del(pim, mg);
-       switch (result) {
-       case PIM_MSDP_ERR_NONE:
-               break;
-       case PIM_MSDP_ERR_NO_MG:
-               vty_out(vty, "%% mesh-group does not exist\n");
-               break;
-       default:
-               vty_out(vty, "%% mesh-group source del failed\n");
-       }
+       nb_cli_enqueue_change(vty, msdp_mesh_group_name_xpath, NB_OP_MODIFY,
+                             argv[3]->arg);
+       nb_cli_enqueue_change(vty, msdp_mesh_source_ip_xpath, NB_OP_MODIFY,
+                             argv[5]->arg);
 
-       return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_msdp_mesh_group_source,
@@ -9968,9 +10116,69 @@ DEFUN (no_ip_msdp_mesh_group_source,
        "mesh group source\n"
        "mesh group local address\n")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       char msdp_mesh_xpath[XPATH_MAXLEN];
+       char source_xpath[XPATH_MAXLEN];
+       char group_member_xpath[XPATH_MAXLEN];
+       char mesh_group_name_xpath[XPATH_MAXLEN];
+       const char *mesh_group_name;
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       snprintf(msdp_mesh_xpath, sizeof(msdp_mesh_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(msdp_mesh_xpath, "/msdp-mesh-group", sizeof(msdp_mesh_xpath));
+
+       snprintf(source_xpath, sizeof(source_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(source_xpath, "/msdp-mesh-group/source-ip",
+               sizeof(source_xpath));
+
+       snprintf(group_member_xpath,
+                sizeof(group_member_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(group_member_xpath, "/msdp-mesh-group/member-ip",
+               sizeof(group_member_xpath));
+
+       snprintf(mesh_group_name_xpath, sizeof(mesh_group_name_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
+               sizeof(mesh_group_name_xpath));
+
+       if (yang_dnode_exists(running_config->dnode, mesh_group_name_xpath)
+           == true) {
+               mesh_group_name = yang_dnode_get_string(running_config->dnode,
+                                                       mesh_group_name_xpath);
+               if (strcmp(mesh_group_name, argv[4]->arg)) {
+                       vty_out(vty, "%% mesh-group does not exist\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+       }
 
-       return ip_no_msdp_mesh_group_source_cmd_worker(pim, vty, argv[4]->arg);
+       if (!yang_dnode_exists(vty->candidate_config->dnode,
+                              group_member_xpath)) {
+               nb_cli_enqueue_change(vty, msdp_mesh_xpath, NB_OP_DESTROY,
+                                     NULL);
+               return nb_cli_apply_changes(vty, NULL);
+       }
+       nb_cli_enqueue_change(vty, source_xpath, NB_OP_DESTROY, NULL);
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_ip_msdp_mesh_group,
@@ -9982,12 +10190,50 @@ DEFUN (no_ip_msdp_mesh_group,
        "Delete MSDP mesh-group\n"
        "mesh group name")
 {
-       PIM_DECLVAR_CONTEXT(vrf, pim);
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
+       const char *mesh_group_name;
+       char xpath[XPATH_MAXLEN];
+       char msdp_mesh_xpath[XPATH_MAXLEN];
+
+       if (vty->xpath_index) {
+               vrf_dnode =
+                       yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (!vrf_dnode) {
+                       vty_out(vty,
+                               "%% Failed to get vrf dnode in candidate db\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+       } else
+               vrfname = VRF_DEFAULT_NAME;
+
+       if (argc == 5) {
+               snprintf(xpath, sizeof(xpath), FRR_PIM_AF_XPATH, "frr-pim:pimd",
+                        "pim", vrfname, "frr-routing:ipv4");
+               strlcat(xpath, "/msdp-mesh-group/mesh-group-name",
+                       sizeof(xpath));
+
+               if (yang_dnode_exists(running_config->dnode, xpath) == true) {
+                       mesh_group_name =
+                               yang_dnode_get_string(running_config->dnode,
+                                                     xpath);
+
+                       if (strcmp(mesh_group_name, argv[4]->arg)) {
+                               vty_out(vty, "%% mesh-group does not exist\n");
+                               return CMD_WARNING_CONFIG_FAILED;
+                       }
+               }
+       }
 
-       if (argc == 5)
-               return ip_no_msdp_mesh_group_cmd_worker(pim, vty, argv[4]->arg);
-       else
-               return ip_no_msdp_mesh_group_cmd_worker(pim, vty, NULL);
+       snprintf(msdp_mesh_xpath, sizeof(msdp_mesh_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       strlcat(msdp_mesh_xpath, "/msdp-mesh-group", sizeof(msdp_mesh_xpath));
+
+       nb_cli_enqueue_change(vty, msdp_mesh_xpath, NB_OP_DESTROY, NULL);
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 static void print_empty_json_obj(struct vty *vty)
@@ -10062,7 +10308,7 @@ static void ip_msdp_show_mesh_group(struct pim_instance *pim, struct vty *vty,
        if (uj) {
                json_object_object_add(json, mg->mesh_group_name, json_mg_row);
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -10170,7 +10416,7 @@ static void ip_msdp_show_peers(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -10275,7 +10521,7 @@ static void ip_msdp_show_peers_detail(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -10423,7 +10669,7 @@ static void ip_msdp_show_sa(struct pim_instance *pim, struct vty *vty, bool uj)
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -10516,7 +10762,7 @@ static void ip_msdp_show_sa_detail(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -10601,7 +10847,7 @@ static void ip_msdp_show_sa_addr(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -10630,7 +10876,7 @@ static void ip_msdp_show_sa_sg(struct pim_instance *pim, struct vty *vty,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -10657,10 +10903,10 @@ DEFUN (show_ip_msdp_sa_sg,
                return CMD_WARNING;
 
        char *src_ip = argv_find(argv, argc, "A.B.C.D", &idx) ? argv[idx++]->arg
-                                                             : NULL;
+               : NULL;
        char *grp_ip = idx < argc && argv_find(argv, argc, "A.B.C.D", &idx)
-                              ? argv[idx]->arg
-                              : NULL;
+               ? argv[idx]->arg
+               : NULL;
 
        if (src_ip && grp_ip)
                ip_msdp_show_sa_sg(vrf->info, vty, src_ip, grp_ip, uj);
@@ -10690,10 +10936,10 @@ DEFUN (show_ip_msdp_sa_sg_vrf_all,
        int idx = 2;
 
        char *src_ip = argv_find(argv, argc, "A.B.C.D", &idx) ? argv[idx++]->arg
-                                                             : NULL;
+               : NULL;
        char *grp_ip = idx < argc && argv_find(argv, argc, "A.B.C.D", &idx)
-                              ? argv[idx]->arg
-                              : NULL;
+               ? argv[idx]->arg
+               : NULL;
 
        if (uj)
                vty_out(vty, "{ ");
@@ -10728,7 +10974,7 @@ struct pim_sg_cache_walk_data {
 };
 
 static void pim_show_vxlan_sg_entry(struct pim_vxlan_sg *vxlan_sg,
-                        struct pim_sg_cache_walk_data *cwd)
+                                   struct pim_sg_cache_walk_data *cwd)
 {
        struct vty *vty = cwd->vty;
        json_object *json = cwd->json;
@@ -10745,7 +10991,7 @@ static void pim_show_vxlan_sg_entry(struct pim_vxlan_sg *vxlan_sg,
                oif_name = vxlan_sg->term_oif?vxlan_sg->term_oif->name:"";
 
        if (cwd->addr_match && (vxlan_sg->sg.src.s_addr != cwd->addr.s_addr) &&
-                       (vxlan_sg->sg.grp.s_addr != cwd->addr.s_addr)) {
+           (vxlan_sg->sg.grp.s_addr != cwd->addr.s_addr)) {
                return;
        }
        pim_inet4_dump("<src?>", vxlan_sg->sg.src, src_str, sizeof(src_str));
@@ -10756,7 +11002,7 @@ static void pim_show_vxlan_sg_entry(struct pim_vxlan_sg *vxlan_sg,
                if (!cwd->json_group) {
                        cwd->json_group = json_object_new_object();
                        json_object_object_add(json, grp_str,
-                                       cwd->json_group);
+                                              cwd->json_group);
                }
 
                json_row = json_object_new_object();
@@ -10771,19 +11017,19 @@ static void pim_show_vxlan_sg_entry(struct pim_vxlan_sg *vxlan_sg,
                json_object_object_add(cwd->json_group, src_str, json_row);
        } else {
                vty_out(vty, "%-15s %-15s %-15s %-15s %-5s\n",
-                               src_str, grp_str, iif_name, oif_name,
-                               installed?"I":"");
+                       src_str, grp_str, iif_name, oif_name,
+                       installed?"I":"");
        }
 }
 
 static void pim_show_vxlan_sg_hash_entry(struct hash_bucket *backet, void *arg)
 {
        pim_show_vxlan_sg_entry((struct pim_vxlan_sg *)backet->data,
-                (struct pim_sg_cache_walk_data *)arg);
+                               (struct pim_sg_cache_walk_data *)arg);
 }
 
 static void pim_show_vxlan_sg(struct pim_instance *pim,
-               struct vty *vty, bool uj)
+                             struct vty *vty, bool uj)
 {
        json_object *json = NULL;
        struct pim_sg_cache_walk_data cwd;
@@ -10803,13 +11049,14 @@ static void pim_show_vxlan_sg(struct pim_instance *pim,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                       json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
 
 static void pim_show_vxlan_sg_match_addr(struct pim_instance *pim,
-               struct vty *vty, char *addr_str, bool uj)
+                                        struct vty *vty, char *addr_str,
+                                        bool uj)
 {
        json_object *json = NULL;
        struct pim_sg_cache_walk_data cwd;
@@ -10819,7 +11066,7 @@ static void pim_show_vxlan_sg_match_addr(struct pim_instance *pim,
        result = inet_pton(AF_INET, addr_str, &cwd.addr);
        if (result <= 0) {
                vty_out(vty, "Bad address %s: errno=%d: %s\n", addr_str,
-                               errno, safe_strerror(errno));
+                       errno, safe_strerror(errno));
                return;
        }
 
@@ -10838,13 +11085,14 @@ static void pim_show_vxlan_sg_match_addr(struct pim_instance *pim,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                       json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
 
 static void pim_show_vxlan_sg_one(struct pim_instance *pim,
-               struct vty *vty, char *src_str, char *grp_str, bool uj)
+                                 struct vty *vty, char *src_str, char *grp_str,
+                                 bool uj)
 {
        json_object *json = NULL;
        struct prefix_sg sg;
@@ -10857,13 +11105,13 @@ static void pim_show_vxlan_sg_one(struct pim_instance *pim,
        result = inet_pton(AF_INET, src_str, &sg.src);
        if (result <= 0) {
                vty_out(vty, "Bad src address %s: errno=%d: %s\n", src_str,
-                               errno, safe_strerror(errno));
+                       errno, safe_strerror(errno));
                return;
        }
        result = inet_pton(AF_INET, grp_str, &sg.grp);
        if (result <= 0) {
                vty_out(vty, "Bad grp address %s: errno=%d: %s\n", grp_str,
-                               errno, safe_strerror(errno));
+                       errno, safe_strerror(errno));
                return;
        }
 
@@ -10893,7 +11141,7 @@ static void pim_show_vxlan_sg_one(struct pim_instance *pim,
                                json_object_boolean_true_add(json, "installed");
                        else
                                json_object_boolean_false_add(json,
-                                       "installed");
+                                                             "installed");
                } else {
                        vty_out(vty, "SG : %s\n", vxlan_sg->sg_str);
                        vty_out(vty, "  Input     : %s\n", iif_name);
@@ -10905,7 +11153,7 @@ static void pim_show_vxlan_sg_one(struct pim_instance *pim,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                       json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -10947,7 +11195,7 @@ DEFUN (show_ip_pim_vxlan_sg,
 }
 
 static void pim_show_vxlan_sg_work(struct pim_instance *pim,
-               struct vty *vty, bool uj)
+                                  struct vty *vty, bool uj)
 {
        json_object *json = NULL;
        struct pim_sg_cache_walk_data cwd;
@@ -10970,7 +11218,7 @@ static void pim_show_vxlan_sg_work(struct pim_instance *pim,
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                       json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -11000,86 +11248,108 @@ DEFUN_HIDDEN (show_ip_pim_vxlan_sg_work,
 }
 
 DEFUN_HIDDEN (no_ip_pim_mlag,
-       no_ip_pim_mlag_cmd,
-       "no ip pim mlag",
-       NO_STR
-       IP_STR
-       PIM_STR
-       "MLAG\n")
+             no_ip_pim_mlag_cmd,
+             "no ip pim mlag",
+             NO_STR
+             IP_STR
+             PIM_STR
+             "MLAG\n")
 {
-       struct in_addr addr;
+       char mlag_xpath[XPATH_MAXLEN];
 
-       addr.s_addr = 0;
-       pim_vxlan_mlag_update(true/*mlag_enable*/,
-               false/*peer_state*/, MLAG_ROLE_NONE,
-               NULL/*peerlink*/, &addr);
+       snprintf(mlag_xpath, sizeof(mlag_xpath), FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
+       strlcat(mlag_xpath, "/mlag", sizeof(mlag_xpath));
 
-       return CMD_SUCCESS;
+       nb_cli_enqueue_change(vty, mlag_xpath, NB_OP_DESTROY, NULL);
+
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN_HIDDEN (ip_pim_mlag,
-       ip_pim_mlag_cmd,
-       "ip pim mlag INTERFACE role [primary|secondary] state [up|down] addr A.B.C.D",
-       IP_STR
-       PIM_STR
-       "MLAG\n"
-       "peerlink sub interface\n"
-       "MLAG role\n"
-       "MLAG role primary\n"
-       "MLAG role secondary\n"
-       "peer session state\n"
-       "peer session state up\n"
-       "peer session state down\n"
-       "configure PIP\n"
-       "unique ip address\n")
+             ip_pim_mlag_cmd,
+             "ip pim mlag INTERFACE role [primary|secondary] state [up|down] addr A.B.C.D",
+             IP_STR
+             PIM_STR
+             "MLAG\n"
+             "peerlink sub interface\n"
+             "MLAG role\n"
+             "MLAG role primary\n"
+             "MLAG role secondary\n"
+             "peer session state\n"
+             "peer session state up\n"
+             "peer session state down\n"
+             "configure PIP\n"
+             "unique ip address\n")
 {
-       struct interface *ifp;
-       const char *peerlink;
-       uint32_t role;
        int idx;
-       bool peer_state;
-       int result;
-       struct in_addr reg_addr;
+       char mlag_peerlink_rif_xpath[XPATH_MAXLEN];
+       char mlag_my_role_xpath[XPATH_MAXLEN];
+       char mlag_peer_state_xpath[XPATH_MAXLEN];
+       char mlag_reg_address_xpath[XPATH_MAXLEN];
+
+       snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
+       strlcat(mlag_peerlink_rif_xpath, "/mlag/peerlink-rif",
+               sizeof(mlag_peerlink_rif_xpath));
 
        idx = 3;
-       peerlink = argv[idx]->arg;
-       ifp = if_lookup_by_name(peerlink, VRF_DEFAULT);
-       if (!ifp) {
-               vty_out(vty, "No such interface name %s\n", peerlink);
-               return CMD_WARNING;
-       }
+       nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY,
+                             argv[idx]->arg);
+
+       snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
+       strlcat(mlag_my_role_xpath, "/mlag/my-role",
+               sizeof(mlag_my_role_xpath));
 
        idx += 2;
        if (!strcmp(argv[idx]->arg, "primary")) {
-               role = MLAG_ROLE_PRIMARY;
+               nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY,
+                                     "MLAG_ROLE_PRIMARY");
+
        } else if (!strcmp(argv[idx]->arg, "secondary")) {
-               role = MLAG_ROLE_SECONDARY;
+               nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY,
+                                     "MLAG_ROLE_SECONDARY");
+
        } else {
                vty_out(vty, "unknown MLAG role %s\n", argv[idx]->arg);
                return CMD_WARNING;
        }
 
+       snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
+       strlcat(mlag_peer_state_xpath, "/mlag/peer-state",
+               sizeof(mlag_peer_state_xpath));
+
        idx += 2;
        if (!strcmp(argv[idx]->arg, "up")) {
-               peer_state = true;
+               nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY,
+                                     "true");
+
        } else if (strcmp(argv[idx]->arg, "down")) {
-               peer_state = false;
+               nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY,
+                                     "false");
+
        } else {
                vty_out(vty, "unknown MLAG state %s\n", argv[idx]->arg);
                return CMD_WARNING;
        }
 
+       snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath),
+                FRR_PIM_AF_XPATH,
+                "frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
+       strlcat(mlag_reg_address_xpath, "/mlag/reg-address",
+               sizeof(mlag_reg_address_xpath));
+
        idx += 2;
-       result = inet_pton(AF_INET, argv[idx]->arg, &reg_addr);
-       if (result <= 0) {
-               vty_out(vty, "%% Bad reg address %s: errno=%d: %s\n",
-                       argv[idx]->arg,
-                       errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-       pim_vxlan_mlag_update(true, peer_state, role, ifp, &reg_addr);
+       nb_cli_enqueue_change(vty, mlag_reg_address_xpath, NB_OP_MODIFY,
+                             argv[idx]->arg);
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 void pim_cmd_init(void)
@@ -11272,6 +11542,7 @@ void pim_cmd_init(void)
        install_element(ENABLE_NODE, &clear_ip_pim_interface_traffic_cmd);
        install_element(ENABLE_NODE, &clear_ip_pim_oil_cmd);
        install_element(ENABLE_NODE, &clear_ip_pim_statistics_cmd);
+       install_element(ENABLE_NODE, &clear_ip_pim_bsr_db_cmd);
 
        install_element(ENABLE_NODE, &show_debugging_pim_cmd);
 
index b2971e5f1feb6bc124fe088c617f111e2c75b04d..fc0f514a49a4a25754827c8f3b192fc20c51a9c8 100644 (file)
@@ -258,7 +258,7 @@ void pim_ifchannel_delete_all(struct interface *ifp)
        }
 }
 
-static void delete_on_noinfo(struct pim_ifchannel *ch)
+void delete_on_noinfo(struct pim_ifchannel *ch)
 {
        if (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO
            && ch->ifjoin_state == PIM_IFJOIN_NOINFO
@@ -550,8 +550,21 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
        struct pim_upstream *up;
 
        ch = pim_ifchannel_find(ifp, sg);
-       if (ch)
+       if (ch) {
+               if (up_flags == PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
+                       PIM_IF_FLAG_SET_PROTO_PIM(ch->flags);
+
+               if (up_flags == PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
+                       PIM_IF_FLAG_SET_PROTO_IGMP(ch->flags);
+
+               if (ch->upstream)
+                       ch->upstream->flags |= up_flags;
+               else if (PIM_DEBUG_EVENTS)
+                       zlog_debug("%s:%s No Upstream found", __func__,
+                                  pim_str_sg_dump(sg));
+
                return ch;
+       }
 
        pim_ifp = ifp->info;
 
@@ -642,6 +655,12 @@ static void ifjoin_to_noinfo(struct pim_ifchannel *ch, bool ch_del)
 {
        pim_forward_stop(ch, !ch_del);
        pim_ifchannel_ifjoin_switch(__func__, ch, PIM_IFJOIN_NOINFO);
+
+       if (ch->upstream)
+               PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(ch->upstream->flags);
+
+       PIM_IF_FLAG_UNSET_PROTO_PIM(ch->flags);
+
        if (ch_del)
                delete_on_noinfo(ch);
 }
@@ -1272,6 +1291,13 @@ void pim_ifchannel_local_membership_del(struct interface *ifp,
                         * parent' delete_no_info */
                }
        }
+
+       /* Resettng the IGMP flags here */
+       if (orig->upstream)
+               PIM_UPSTREAM_FLAG_UNSET_SRC_IGMP(orig->upstream->flags);
+
+       PIM_IF_FLAG_UNSET_PROTO_IGMP(orig->flags);
+
        delete_on_noinfo(orig);
 }
 
index 425622b79ed3b8afd04065cf19253f4a20a7fbd2..7ec8191e568704d07f42277194405b8a42c60b05 100644 (file)
@@ -173,4 +173,5 @@ int pim_ifchannel_compare(const struct pim_ifchannel *ch1,
                          const struct pim_ifchannel *ch2);
 
 unsigned int pim_ifchannel_hash_key(const void *arg);
+void delete_on_noinfo(struct pim_ifchannel *ch);
 #endif /* PIM_IFCHANNEL_H */
index 9924e335b00839a82d6da220582b337dd1677604..73e42e9d83867785bc9830a3471bb8c787851dca 100644 (file)
@@ -558,8 +558,8 @@ int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len)
                                           igmp_msg, igmp_msg_len);
 
        case PIM_IGMP_V2_LEAVE_GROUP:
-               return igmp_v2_recv_leave(igmp, ip_hdr->ip_src, from_str,
-                                         igmp_msg, igmp_msg_len);
+               return igmp_v2_recv_leave(igmp, ip_hdr, from_str, igmp_msg,
+                                         igmp_msg_len);
 
        case PIM_IGMP_MTRACE_RESPONSE:
                return igmp_mtrace_recv_response(igmp, ip_hdr, ip_hdr->ip_src,
index d836c66cbbc5d91c2f53bcb9d9506c2f7ed1bbc9..7f3c7a0f8cb8c0902b6d42b8e9fbfe764b8a924b 100644 (file)
@@ -158,12 +158,13 @@ int igmp_v2_recv_report(struct igmp_sock *igmp, struct in_addr from,
        return 0;
 }
 
-int igmp_v2_recv_leave(struct igmp_sock *igmp, struct in_addr from,
+int igmp_v2_recv_leave(struct igmp_sock *igmp, struct ip *ip_hdr,
                       const char *from_str, char *igmp_msg, int igmp_msg_len)
 {
        struct interface *ifp = igmp->interface;
        struct in_addr group_addr;
        char group_str[INET_ADDRSTRLEN];
+       struct in_addr from = ip_hdr->ip_src;
 
        on_trace(__func__, igmp->interface, from);
 
@@ -184,8 +185,6 @@ int igmp_v2_recv_leave(struct igmp_sock *igmp, struct in_addr from,
                return -1;
        }
 
-       /* Collecting IGMP Rx stats */
-       igmp->rx_stats.leave_v2++;
 
        memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
 
@@ -195,6 +194,32 @@ int igmp_v2_recv_leave(struct igmp_sock *igmp, struct in_addr from,
                zlog_debug("Recv IGMPv2 LEAVE from %s on %s for %s", from_str,
                           ifp->name, group_str);
        }
+       /*
+        * As per RFC 2236, section 9:
+        Message Type                  Destination Group
+        ------------                  -----------------
+        General Query                 ALL-SYSTEMS (224.0.0.1)
+        Group-Specific Query          The group being queried
+        Membership Report             The group being reported
+        Leave Message                 ALL-ROUTERS (224.0.0.2)
+
+        Note: in older (i.e., non-standard and now obsolete) versions of
+        IGMPv2, hosts send Leave Messages to the group being left.  A
+        router SHOULD accept Leave Messages addressed to the group being
+        left in the interests of backwards compatibility with such hosts.
+        In all cases, however, hosts MUST send to the ALL-ROUTERS address
+        to be compliant with this specification.
+       */
+       if ((ntohl(ip_hdr->ip_dst.s_addr) != INADDR_ALLRTRS_GROUP)
+           && (ip_hdr->ip_dst.s_addr != group_addr.s_addr)) {
+               if (PIM_DEBUG_IGMP_EVENTS)
+                       zlog_debug(
+                               "IGMPv2 Leave message is ignored since received on address other than ALL-ROUTERS or Group-address");
+               return -1;
+       }
+
+       /* Collecting IGMP Rx stats */
+       igmp->rx_stats.leave_v2++;
 
        /*
         * RFC 3376
index f0a6fdc5fb31708d68d2146ce5e8141f8e542c53..29591ff16cb12ade7c6bdd8acf799c123af5b68a 100644 (file)
@@ -29,7 +29,7 @@ void igmp_v2_send_query(struct igmp_group *group, int fd, const char *ifname,
 int igmp_v2_recv_report(struct igmp_sock *igmp, struct in_addr from,
                        const char *from_str, char *igmp_msg, int igmp_msg_len);
 
-int igmp_v2_recv_leave(struct igmp_sock *igmp, struct in_addr from,
+int igmp_v2_recv_leave(struct igmp_sock *igmp, struct ip *ip_hdr,
                       const char *from_str, char *igmp_msg, int igmp_msg_len);
 
 #endif /* PIM_IGMPV2_H */
index f54d5bf9bfe48b448cc4f40a7473566518e296bd..2766a6d2b51e9d5e0c376c2b8cf0dec48bb3c810 100644 (file)
@@ -350,8 +350,11 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
                                            == PIM_IFJOIN_PRUNE_PENDING_TMP)
                                                THREAD_OFF(
                                                        child->t_ifjoin_prune_pending_timer);
+                                       THREAD_OFF(
+                                               child->t_ifjoin_expiry_timer);
                                        PIM_IF_FLAG_UNSET_S_G_RPT(child->flags);
                                        child->ifjoin_state = PIM_IFJOIN_NOINFO;
+                                       delete_on_noinfo(child);
                                }
                        }
 
index 5279a008556f5ea2ccea142a21923bd366ccfcaf..d95d9dd25dccae3ef08c0feb96907be88dc309db 100644 (file)
@@ -360,11 +360,9 @@ void pim_jp_agg_switch_interface(struct pim_rpf *orpf, struct pim_rpf *nrpf,
 void pim_jp_agg_single_upstream_send(struct pim_rpf *rpf,
                                     struct pim_upstream *up, bool is_join)
 {
-       static struct list *groups = NULL;
-       static struct pim_jp_agg_group jag;
-       static struct pim_jp_sources js;
-
-       static bool first = true;
+       struct list groups, sources;
+       struct pim_jp_agg_group jag;
+       struct pim_jp_sources js;
 
        /* skip JP upstream messages if source is directly connected */
        if (!up || !rpf->source_nexthop.interface ||
@@ -373,19 +371,19 @@ void pim_jp_agg_single_upstream_send(struct pim_rpf *rpf,
                if_is_loopback_or_vrf(rpf->source_nexthop.interface))
                return;
 
-       if (first) {
-               groups = list_new();
-               jag.sources = list_new();
-
-               listnode_add(groups, &jag);
-               listnode_add(jag.sources, &js);
+       memset(&groups, 0, sizeof(groups));
+       memset(&sources, 0, sizeof(sources));
+       jag.sources = &sources;
 
-               first = false;
-       }
+       listnode_add(&groups, &jag);
+       listnode_add(jag.sources, &js);
 
        jag.group.s_addr = up->sg.grp.s_addr;
        js.up = up;
        js.is_join = is_join;
 
-       pim_joinprune_send(rpf, groups);
+       pim_joinprune_send(rpf, &groups);
+
+       list_delete_all_node(jag.sources);
+       list_delete_all_node(&groups);
 }
index 132d913f68e4b72f8eaf4f008f65b6f25e9d2145..9c11cc47d58e2e34eeea3570bb7e08548cc36924 100644 (file)
 #include "vrf.h"
 #include "libfrr.h"
 #include "routemap.h"
+#include "routing_nb.h"
 
 #include "pimd.h"
 #include "pim_instance.h"
-#include "pim_version.h"
 #include "pim_signals.h"
 #include "pim_zebra.h"
 #include "pim_msdp.h"
@@ -49,6 +49,7 @@
 #include "pim_bfd.h"
 #include "pim_mlag.h"
 #include "pim_errors.h"
+#include "pim_nb.h"
 
 extern struct host host;
 
@@ -77,6 +78,10 @@ static const struct frr_yang_module_info *const pimd_yang_modules[] = {
        &frr_interface_info,
        &frr_route_map_info,
        &frr_vrf_info,
+       &frr_routing_info,
+       &frr_pim_info,
+       &frr_pim_rp_info,
+       &frr_igmp_info,
 };
 
 FRR_DAEMON_INFO(pimd, PIM, .vty_port = PIMD_VTY_PORT,
@@ -137,6 +142,9 @@ int main(int argc, char **argv, char **envp)
        pim_bfd_init();
        pim_mlag_init();
 
+       hook_register(routing_conf_event,
+                     routing_control_plane_protocols_name_validate);
+
        frr_config_fork();
 
 #ifdef PIM_DEBUG_BYDEFAULT
index 0bccba397b1463732226af7d52bd2f46efbd352e..23259900b7d7925aea2854d47bab2cfeca0f0bb9 100644 (file)
@@ -628,7 +628,7 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
                ifaddr = connected_src->u.prefix4;
                igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, ifaddr);
 
-               if (PIM_DEBUG_MROUTE) {
+               if (PIM_DEBUG_IGMP_PACKETS) {
                        zlog_debug(
                                "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4",
                                __func__, pim->vrf->name, ifp->name, igmp,
diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c
new file mode 100644 (file)
index 0000000..8ca0e07
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2020 VmWare
+ *                    Sarita Patra
+ *
+ * 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 "northbound.h"
+#include "libfrr.h"
+#include "vrf.h"
+#include "pimd/pim_nb.h"
+
+/* clang-format off */
+const struct frr_yang_module_info frr_pim_info = {
+       .name = "frr-pim",
+       .nodes = {
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/ecmp",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_ecmp_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/ecmp-rebalance",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_ecmp_rebalance_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-pim:pim/join-prune-interval",
+                       .cbs = {
+                               .modify = pim_join_prune_interval_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/keep-alive-timer",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_keep_alive_timer_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/rp-keep-alive-timer",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_rp_keep_alive_timer_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-pim:pim/packets",
+                       .cbs = {
+                               .modify = pim_packets_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-pim:pim/register-suppress-time",
+                       .cbs = {
+                               .modify = pim_register_suppress_time_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family",
+                       .cbs = {
+                               .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/send-v6-secondary",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover",
+                       .cbs = {
+                               .apply_finish = routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_apply_finish,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover/spt-action",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_action_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover/spt-infinity-prefix-list",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ssm-prefix-list",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ssm-pingd-source-ip",
+                       .cbs = {
+                               .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group",
+                       .cbs = {
+                               .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/mesh-group-name",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/member-ip",
+                       .cbs = {
+                               .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/source-ip",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer",
+                       .cbs = {
+                               .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/source-ip",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag",
+                       .cbs = {
+                               .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy,
+                               .apply_finish = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_apply_finish,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/peerlink-rif",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/reg-address",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/my-role",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_my_role_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/peer-state",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peer_state_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/register-accept-list",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim",
+                       .cbs = {
+                               .create = lib_interface_pim_create,
+                               .destroy = lib_interface_pim_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/pim-enable",
+                       .cbs = {
+                               .modify = lib_interface_pim_pim_enable_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/dr-priority",
+                       .cbs = {
+                               .modify = lib_interface_pim_dr_priority_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/hello-interval",
+                       .cbs = {
+                               .modify = lib_interface_pim_hello_interval_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/hello-holdtime",
+                       .cbs = {
+                               .modify = lib_interface_pim_hello_holdtime_modify,
+                               .destroy = lib_interface_pim_hello_holdtime_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd",
+                       .cbs = {
+                               .create = lib_interface_pim_bfd_create,
+                               .destroy = lib_interface_pim_bfd_destroy,
+                               .apply_finish = lib_interface_pim_bfd_apply_finish,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd/min-rx-interval",
+                       .cbs = {
+                               .modify = lib_interface_pim_bfd_min_rx_interval_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd/min-tx-interval",
+                       .cbs = {
+                               .modify = lib_interface_pim_bfd_min_tx_interval_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd/detect_mult",
+                       .cbs = {
+                               .modify = lib_interface_pim_bfd_detect_mult_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/bsm",
+                       .cbs = {
+                               .modify = lib_interface_pim_bsm_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/unicast-bsm",
+                       .cbs = {
+                               .modify = lib_interface_pim_unicast_bsm_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/active-active",
+                       .cbs = {
+                               .modify = lib_interface_pim_active_active_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family",
+                       .cbs = {
+                               .create = lib_interface_pim_address_family_create,
+                               .destroy = lib_interface_pim_address_family_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/use-source",
+                       .cbs = {
+                               .modify = lib_interface_pim_address_family_use_source_modify,
+                               .destroy = lib_interface_pim_address_family_use_source_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/multicast-boundary-oil",
+                       .cbs = {
+                               .modify = lib_interface_pim_address_family_multicast_boundary_oil_modify,
+                               .destroy = lib_interface_pim_address_family_multicast_boundary_oil_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/mroute",
+                       .cbs = {
+                               .create = lib_interface_pim_address_family_mroute_create,
+                               .destroy = lib_interface_pim_address_family_mroute_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/mroute/oif",
+                       .cbs = {
+                               .modify = lib_interface_pim_address_family_mroute_oif_modify,
+                               .destroy = lib_interface_pim_address_family_mroute_oif_destroy,
+                       }
+               },
+               {
+                       .xpath = NULL,
+               },
+       }
+};
+
+/* clang-format off */
+const struct frr_yang_module_info frr_pim_rp_info = {
+       .name = "frr-pim-rp",
+       .nodes = {
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/static-rp/rp-list",
+                       .cbs = {
+                               .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/static-rp/rp-list/group-list",
+                       .cbs = {
+                               .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/static-rp/rp-list/prefix-list",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_destroy,
+                       }
+               },
+               {
+                       .xpath = NULL,
+               },
+       }
+};
+
+/* clang-format off */
+const struct frr_yang_module_info frr_igmp_info = {
+       .name = "frr-igmp",
+       .nodes = {
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-igmp:igmp",
+                       .cbs = {
+                               .create = lib_interface_igmp_create,
+                               .destroy = lib_interface_igmp_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/igmp-enable",
+                       .cbs = {
+                               .modify = lib_interface_igmp_igmp_enable_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/version",
+                       .cbs = {
+                               .modify = lib_interface_igmp_version_modify,
+                               .destroy = lib_interface_igmp_version_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/query-interval",
+                       .cbs = {
+                               .modify = lib_interface_igmp_query_interval_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/query-max-response-time",
+                       .cbs = {
+                               .modify = lib_interface_igmp_query_max_response_time_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/last-member-query-interval",
+                       .cbs = {
+                               .modify = lib_interface_igmp_last_member_query_interval_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/robustness-variable",
+                       .cbs = {
+                               .modify = lib_interface_igmp_robustness_variable_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/address-family",
+                       .cbs = {
+                               .create = lib_interface_igmp_address_family_create,
+                               .destroy = lib_interface_igmp_address_family_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/address-family/static-group",
+                       .cbs = {
+                               .create = lib_interface_igmp_address_family_static_group_create,
+                               .destroy = lib_interface_igmp_address_family_static_group_destroy,
+                       }
+               },
+               {
+                       .xpath = NULL,
+               },
+       }
+};
diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h
new file mode 100644 (file)
index 0000000..78eb680
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2020 VmWare
+ *                    Sarita Patra
+ *
+ * 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_PIM_NB_H_
+#define _FRR_PIM_NB_H_
+
+extern const struct frr_yang_module_info frr_pim_info;
+extern const struct frr_yang_module_info frr_pim_rp_info;
+extern const struct frr_yang_module_info frr_igmp_info;
+
+/* frr-pim prototypes*/
+int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_rebalance_modify(
+       struct nb_cb_modify_args *args);
+int pim_join_prune_interval_modify(struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_keep_alive_timer_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_rp_keep_alive_timer_modify(
+       struct nb_cb_modify_args *args);
+int pim_packets_modify(struct nb_cb_modify_args *args);
+int pim_register_suppress_time_modify(struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_destroy(
+       struct nb_cb_destroy_args *args);
+void routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_apply_finish(
+       struct nb_cb_apply_finish_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_action_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy(
+       struct nb_cb_destroy_args *args);
+void routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_apply_finish(
+       struct nb_cb_apply_finish_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_my_role_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peer_state_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_destroy(
+       struct nb_cb_destroy_args *args);
+int lib_interface_pim_dr_priority_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_pim_create(struct nb_cb_create_args *args);
+int lib_interface_pim_destroy(struct nb_cb_destroy_args *args);
+int lib_interface_pim_pim_enable_modify(struct nb_cb_modify_args *args);
+int lib_interface_pim_hello_interval_modify(struct nb_cb_modify_args *args);
+int lib_interface_pim_hello_holdtime_modify(struct nb_cb_modify_args *args);
+int lib_interface_pim_hello_holdtime_destroy(struct nb_cb_destroy_args *args);
+int lib_interface_pim_bfd_create(struct nb_cb_create_args *args);
+int lib_interface_pim_bfd_destroy(struct nb_cb_destroy_args *args);
+void lib_interface_pim_bfd_apply_finish(struct nb_cb_apply_finish_args *args);
+int lib_interface_pim_bfd_min_rx_interval_modify(struct nb_cb_modify_args *args);
+int lib_interface_pim_bfd_min_tx_interval_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args);
+int lib_interface_pim_bsm_modify(struct nb_cb_modify_args *args);
+int lib_interface_pim_unicast_bsm_modify(struct nb_cb_modify_args *args);
+int lib_interface_pim_active_active_modify(struct nb_cb_modify_args *args);
+int lib_interface_pim_address_family_create(struct nb_cb_create_args *args);
+int lib_interface_pim_address_family_destroy(struct nb_cb_destroy_args *args);
+int lib_interface_pim_address_family_use_source_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_pim_address_family_use_source_destroy(
+       struct nb_cb_destroy_args *args);
+int lib_interface_pim_address_family_multicast_boundary_oil_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_pim_address_family_multicast_boundary_oil_destroy(
+       struct nb_cb_destroy_args *args);
+int lib_interface_pim_address_family_mroute_create(
+       struct nb_cb_create_args *args);
+int lib_interface_pim_address_family_mroute_destroy(
+       struct nb_cb_destroy_args *args);
+int lib_interface_pim_address_family_mroute_oif_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_pim_address_family_mroute_oif_destroy(
+       struct nb_cb_destroy_args *args);
+
+/* frr-pim-rp prototypes*/
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_destroy(
+       struct nb_cb_destroy_args *args);
+
+/* frr-igmp prototypes*/
+int lib_interface_igmp_create(struct nb_cb_create_args *args);
+int lib_interface_igmp_destroy(struct nb_cb_destroy_args *args);
+int lib_interface_igmp_igmp_enable_modify(struct nb_cb_modify_args *args);
+int lib_interface_igmp_version_modify(struct nb_cb_modify_args *args);
+int lib_interface_igmp_version_destroy(struct nb_cb_destroy_args *args);
+int lib_interface_igmp_query_interval_modify(struct nb_cb_modify_args *args);
+int lib_interface_igmp_query_max_response_time_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_igmp_last_member_query_interval_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_igmp_robustness_variable_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_igmp_address_family_create(struct nb_cb_create_args *args);
+int lib_interface_igmp_address_family_destroy(struct nb_cb_destroy_args *args);
+int lib_interface_igmp_address_family_static_group_create(
+       struct nb_cb_create_args *args);
+int lib_interface_igmp_address_family_static_group_destroy(
+       struct nb_cb_destroy_args *args);
+
+/*
+ * Callback registered with routing_nb lib to validate only
+ * one instance of staticd is allowed
+ */
+int routing_control_plane_protocols_name_validate(
+       struct nb_cb_create_args *args);
+
+#define FRR_PIM_XPATH                                                   \
+       "/frr-routing:routing/control-plane-protocols/"                 \
+       "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/"       \
+       "frr-pim:pim"
+#define FRR_PIM_AF_XPATH                                                \
+       "/frr-routing:routing/control-plane-protocols/"                 \
+       "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/"       \
+       "frr-pim:pim/address-family[address-family='%s']"
+#define FRR_PIM_STATIC_RP_XPATH                                         \
+       "/frr-routing:routing/control-plane-protocols/"                 \
+       "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/"       \
+       "frr-pim:pim/address-family[address-family='%s']/"              \
+       "frr-pim-rp:rp/static-rp/rp-list[rp-address='%s']"
+#define FRR_IGMP_JOIN_XPATH                                             \
+       "./frr-igmp:igmp/address-family[address-family='%s']/"          \
+       "static-group[group-addr='%s'][source-addr='%s']"
+#endif /* _FRR_PIM_NB_H_ */
diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
new file mode 100644 (file)
index 0000000..ba044de
--- /dev/null
@@ -0,0 +1,3050 @@
+/*
+ * Copyright (C) 2020 VmWare
+ *                    Sarita Patra
+ *
+ * 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 "pimd.h"
+#include "pim_nb.h"
+#include "lib/northbound_cli.h"
+#include "pim_igmpv3.h"
+#include "pim_pim.h"
+#include "pim_mlag.h"
+#include "pim_bfd.h"
+#include "pim_static.h"
+#include "pim_ssm.h"
+#include "pim_ssmpingd.h"
+#include "pim_vxlan.h"
+#include "log.h"
+#include "lib_errors.h"
+
+static void pim_if_membership_clear(struct interface *ifp)
+{
+       struct pim_interface *pim_ifp;
+
+       pim_ifp = ifp->info;
+       zassert(pim_ifp);
+
+       if (PIM_IF_TEST_PIM(pim_ifp->options)
+           && PIM_IF_TEST_IGMP(pim_ifp->options)) {
+               return;
+       }
+
+       pim_ifchannel_membership_clear(ifp);
+}
+
+/*
+ * When PIM is disabled on interface, IGMPv3 local membership
+ * information is not injected into PIM interface state.
+
+ * The function pim_if_membership_refresh() fetches all IGMPv3 local
+ * membership information into PIM. It is intented to be called
+ * whenever PIM is enabled on the interface in order to collect missed
+ * local membership information.
+ */
+static void pim_if_membership_refresh(struct interface *ifp)
+{
+       struct pim_interface *pim_ifp;
+       struct listnode *sock_node;
+       struct igmp_sock *igmp;
+
+       pim_ifp = ifp->info;
+       zassert(pim_ifp);
+
+       if (!PIM_IF_TEST_PIM(pim_ifp->options))
+               return;
+       if (!PIM_IF_TEST_IGMP(pim_ifp->options))
+               return;
+
+       /*
+        * First clear off membership from all PIM (S,G) entries on the
+        * interface
+        */
+
+       pim_ifchannel_membership_clear(ifp);
+
+       /*
+        * Then restore PIM (S,G) membership from all IGMPv3 (S,G) entries on
+        * the interface
+        */
+
+       /* scan igmp sockets */
+       for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
+               struct listnode *grpnode;
+               struct igmp_group *grp;
+
+               /* scan igmp groups */
+               for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode,
+                                         grp)) {
+                       struct listnode *srcnode;
+                       struct igmp_source *src;
+
+                       /* scan group sources */
+                       for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
+                                                 srcnode, src)) {
+
+                               if (IGMP_SOURCE_TEST_FORWARDING(
+                                   src->source_flags)) {
+                                       struct prefix_sg sg;
+
+                                       memset(&sg, 0,
+                                              sizeof(struct prefix_sg));
+                                       sg.src = src->source_addr;
+                                       sg.grp = grp->group_addr;
+                                       pim_ifchannel_local_membership_add(
+                                               ifp, &sg, false /*is_vxlan*/);
+                               }
+
+                       } /* scan group sources */
+               }        /* scan igmp groups */
+       }                 /* scan igmp sockets */
+
+       /*
+        * Finally delete every PIM (S,G) entry lacking all state info
+        */
+
+       pim_ifchannel_delete_on_noinfo(ifp);
+}
+
+static int pim_cmd_interface_add(struct interface *ifp)
+{
+       struct pim_interface *pim_ifp = ifp->info;
+
+       if (!pim_ifp)
+               pim_ifp = pim_if_new(ifp, false, true, false, false);
+       else
+               PIM_IF_DO_PIM(pim_ifp->options);
+
+       pim_if_addr_add_all(ifp);
+       pim_if_membership_refresh(ifp);
+
+       pim_if_create_pimreg(pim_ifp->pim);
+       return 1;
+}
+
+static int pim_cmd_interface_delete(struct interface *ifp)
+{
+       struct pim_interface *pim_ifp = ifp->info;
+
+       if (!pim_ifp)
+               return 1;
+
+       PIM_IF_DONT_PIM(pim_ifp->options);
+
+       pim_if_membership_clear(ifp);
+
+       /*
+        * pim_sock_delete() removes all neighbors from
+        * pim_ifp->pim_neighbor_list.
+        */
+       pim_sock_delete(ifp, "pim unconfigured on interface");
+
+       if (!PIM_IF_TEST_IGMP(pim_ifp->options)) {
+               pim_if_addr_del_all(ifp);
+               pim_if_delete(ifp);
+       }
+
+       return 1;
+}
+
+static int interface_pim_use_src_cmd_worker(struct interface *ifp,
+               struct in_addr source_addr,
+               char *errmsg, size_t errmsg_len)
+{
+       int result;
+       int ret = NB_OK;
+
+       result = pim_update_source_set(ifp, source_addr);
+
+       switch (result) {
+       case PIM_SUCCESS:
+               break;
+       case PIM_IFACE_NOT_FOUND:
+               ret = NB_ERR;
+               snprintf(errmsg, errmsg_len,
+                        "Pim not enabled on this interface %s",
+                        ifp->name);
+                       break;
+       case PIM_UPDATE_SOURCE_DUP:
+               ret = NB_ERR;
+               snprintf(errmsg, errmsg_len, "Source already set");
+               break;
+       default:
+               ret = NB_ERR;
+               snprintf(errmsg, errmsg_len, "Source set failed");
+       }
+
+       return ret;
+}
+
+static int pim_cmd_spt_switchover(struct pim_instance *pim,
+               enum pim_spt_switchover spt,
+               const char *plist)
+{
+       pim->spt.switchover = spt;
+
+       switch (pim->spt.switchover) {
+       case PIM_SPT_IMMEDIATE:
+               XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist);
+
+               pim_upstream_add_lhr_star_pimreg(pim);
+               break;
+       case PIM_SPT_INFINITY:
+               pim_upstream_remove_lhr_star_pimreg(pim, plist);
+
+               XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist);
+
+               if (plist)
+                       pim->spt.plist = XSTRDUP(MTYPE_PIM_PLIST_NAME, plist);
+               break;
+       }
+
+       return NB_OK;
+}
+
+static int pim_ssm_cmd_worker(struct pim_instance *pim, const char *plist,
+               char *errmsg, size_t errmsg_len)
+{
+       int result = pim_ssm_range_set(pim, pim->vrf_id, plist);
+       int ret = NB_ERR;
+
+       if (result == PIM_SSM_ERR_NONE)
+               return NB_OK;
+
+       switch (result) {
+       case PIM_SSM_ERR_NO_VRF:
+               snprintf(errmsg, errmsg_len,
+                        "VRF doesn't exist");
+               break;
+       case PIM_SSM_ERR_DUP:
+               snprintf(errmsg, errmsg_len,
+                        "duplicate config");
+               break;
+       default:
+               snprintf(errmsg, errmsg_len,
+                        "ssm range config failed");
+       }
+
+       return ret;
+}
+
+static int ip_no_msdp_mesh_group_cmd_worker(struct pim_instance *pim,
+               const char *mg,
+               char *errmsg, size_t errmsg_len)
+{
+       enum pim_msdp_err result;
+
+       result = pim_msdp_mg_del(pim, mg);
+
+       switch (result) {
+       case PIM_MSDP_ERR_NONE:
+               break;
+       case PIM_MSDP_ERR_NO_MG:
+               snprintf(errmsg, errmsg_len,
+                        "%% mesh-group does not exist");
+               break;
+       default:
+               snprintf(errmsg, errmsg_len,
+                        "mesh-group source del failed");
+       }
+
+       return result ? NB_ERR : NB_OK;
+}
+
+static int ip_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
+               const char *mg,
+               struct in_addr mbr_ip,
+               char *errmsg, size_t errmsg_len)
+{
+       enum pim_msdp_err result;
+       int ret = NB_OK;
+
+       result = pim_msdp_mg_mbr_add(pim, mg, mbr_ip);
+
+       switch (result) {
+       case PIM_MSDP_ERR_NONE:
+               break;
+       case PIM_MSDP_ERR_OOM:
+               ret = NB_ERR;
+               snprintf(errmsg, errmsg_len,
+                        "%% Out of memory");
+               break;
+       case PIM_MSDP_ERR_MG_MBR_EXISTS:
+               ret = NB_ERR;
+               snprintf(errmsg, errmsg_len,
+                        "%% mesh-group member exists");
+               break;
+       case PIM_MSDP_ERR_MAX_MESH_GROUPS:
+               ret = NB_ERR;
+               snprintf(errmsg, errmsg_len,
+                        "%% Only one mesh-group allowed currently");
+               break;
+       default:
+               ret = NB_ERR;
+               snprintf(errmsg, errmsg_len,
+                        "%% member add failed");
+       }
+
+       return ret;
+}
+
+static int ip_no_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
+               const char *mg,
+               struct in_addr mbr_ip,
+               char *errmsg,
+               size_t errmsg_len)
+{
+       enum pim_msdp_err result;
+
+       result = pim_msdp_mg_mbr_del(pim, mg, mbr_ip);
+
+       switch (result) {
+       case PIM_MSDP_ERR_NONE:
+               break;
+       case PIM_MSDP_ERR_NO_MG:
+               snprintf(errmsg, errmsg_len,
+                        "%% mesh-group does not exist");
+               break;
+       case PIM_MSDP_ERR_NO_MG_MBR:
+               snprintf(errmsg, errmsg_len,
+                        "%% mesh-group member does not exist");
+               break;
+       default:
+               snprintf(errmsg, errmsg_len,
+                        "%% mesh-group member del failed");
+       }
+
+       return result ? NB_ERR : NB_OK;
+}
+
+static int ip_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim,
+               const char *mg,
+               struct in_addr src_ip,
+               char *errmsg, size_t errmsg_len)
+{
+       enum pim_msdp_err result;
+
+       result = pim_msdp_mg_src_add(pim, mg, src_ip);
+
+       switch (result) {
+       case PIM_MSDP_ERR_NONE:
+               break;
+       case PIM_MSDP_ERR_OOM:
+               snprintf(errmsg, errmsg_len,
+                        "%% Out of memory");
+               break;
+       case PIM_MSDP_ERR_MAX_MESH_GROUPS:
+               snprintf(errmsg, errmsg_len,
+                        "%% Only one mesh-group allowed currently");
+               break;
+       default:
+               snprintf(errmsg, errmsg_len,
+                        "%% source add failed");
+       }
+
+       return result ? NB_ERR : NB_OK;
+}
+
+static int ip_no_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim,
+               const char *mg,
+               char *errmsg,
+               size_t errmsg_len)
+{
+       enum pim_msdp_err result;
+
+       result = pim_msdp_mg_src_del(pim, mg);
+
+       switch (result) {
+       case PIM_MSDP_ERR_NONE:
+               break;
+       case PIM_MSDP_ERR_NO_MG:
+               snprintf(errmsg, errmsg_len,
+                        "%% mesh-group does not exist");
+               break;
+       default:
+               snprintf(errmsg, errmsg_len,
+                        "%% mesh-group source del failed");
+       }
+
+       return result ? NB_ERR : NB_OK;
+}
+
+static int ip_msdp_peer_cmd_worker(struct pim_instance *pim,
+               struct in_addr peer_addr,
+               struct in_addr local_addr,
+               char *errmsg, size_t errmsg_len)
+{
+       enum pim_msdp_err result;
+       int ret = NB_OK;
+
+       result = pim_msdp_peer_add(pim, peer_addr, local_addr, "default",
+                       NULL /* mp_p */);
+       switch (result) {
+       case PIM_MSDP_ERR_NONE:
+               break;
+       case PIM_MSDP_ERR_OOM:
+               ret = NB_ERR;
+               snprintf(errmsg, errmsg_len,
+                        "%% Out of memory");
+               break;
+       case PIM_MSDP_ERR_PEER_EXISTS:
+               ret = NB_ERR;
+               snprintf(errmsg, errmsg_len,
+                        "%% Peer exists");
+               break;
+       case PIM_MSDP_ERR_MAX_MESH_GROUPS:
+               ret = NB_ERR;
+               snprintf(errmsg, errmsg_len,
+                        "%% Only one mesh-group allowed currently");
+               break;
+       default:
+               ret = NB_ERR;
+               snprintf(errmsg, errmsg_len,
+                        "%% peer add failed");
+       }
+
+       return ret;
+}
+
+static int ip_no_msdp_peer_cmd_worker(struct pim_instance *pim,
+               struct in_addr peer_addr,
+               char *errmsg, size_t errmsg_len)
+{
+       enum pim_msdp_err result;
+
+       result = pim_msdp_peer_del(pim, peer_addr);
+       switch (result) {
+       case PIM_MSDP_ERR_NONE:
+               break;
+       case PIM_MSDP_ERR_NO_PEER:
+               snprintf(errmsg, errmsg_len,
+                        "%% Peer does not exist");
+               break;
+       default:
+               snprintf(errmsg, errmsg_len,
+                        "%% peer del failed");
+       }
+
+       return result ? NB_ERR : NB_OK;
+}
+
+static int pim_rp_cmd_worker(struct pim_instance *pim,
+               struct in_addr rp_addr,
+               struct prefix group, const char *plist,
+               char *errmsg, size_t errmsg_len)
+{
+       char rp_str[INET_ADDRSTRLEN];
+       int result;
+
+       inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str));
+
+       result = pim_rp_new(pim, rp_addr, group, plist, RP_SRC_STATIC);
+
+       if (result == PIM_RP_NO_PATH) {
+               snprintf(errmsg, errmsg_len,
+                        "No Path to RP address specified: %s", rp_str);
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       if (result == PIM_GROUP_OVERLAP) {
+               snprintf(errmsg, errmsg_len,
+                        "Group range specified cannot exact match another");
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       if (result == PIM_GROUP_PFXLIST_OVERLAP) {
+               snprintf(errmsg, errmsg_len,
+                        "This group is already covered by a RP prefix-list");
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       if (result == PIM_RP_PFXLIST_IN_USE) {
+               snprintf(errmsg, errmsg_len,
+                        "The same prefix-list cannot be applied to multiple RPs");
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       return NB_OK;
+}
+
+static int pim_no_rp_cmd_worker(struct pim_instance *pim,
+                               struct in_addr rp_addr, struct prefix group,
+                               const char *plist,
+                               char *errmsg, size_t errmsg_len)
+{
+       char rp_str[INET_ADDRSTRLEN];
+       char group_str[PREFIX2STR_BUFFER];
+       int result;
+
+       inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str));
+       prefix2str(&group, group_str, sizeof(group_str));
+
+       result = pim_rp_del(pim, rp_addr, group, plist, RP_SRC_STATIC);
+
+       if (result == PIM_GROUP_BAD_ADDRESS) {
+               snprintf(errmsg, errmsg_len,
+                        "Bad group address specified: %s", group_str);
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       if (result == PIM_RP_BAD_ADDRESS) {
+               snprintf(errmsg, errmsg_len,
+                        "Bad RP address specified: %s", rp_str);
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       if (result == PIM_RP_NOT_FOUND) {
+               snprintf(errmsg, errmsg_len,
+                        "Unable to find specified RP");
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       return NB_OK;
+}
+
+static bool is_pim_interface(const struct lyd_node *dnode)
+{
+       char if_xpath[XPATH_MAXLEN];
+       const struct lyd_node *pim_enable_dnode;
+       const struct lyd_node *igmp_enable_dnode;
+
+       yang_dnode_get_path(dnode, if_xpath, sizeof(if_xpath));
+       pim_enable_dnode = yang_dnode_get(dnode, "%s/frr-pim:pim/pim-enable",
+                                         if_xpath);
+       igmp_enable_dnode = yang_dnode_get(dnode,
+                                          "%s/frr-igmp:igmp/igmp-enable",
+                                          if_xpath);
+
+       if (((pim_enable_dnode) &&
+            (yang_dnode_get_bool(pim_enable_dnode, "."))) ||
+            ((igmp_enable_dnode) &&
+            (yang_dnode_get_bool(igmp_enable_dnode, "."))))
+               return true;
+
+       return false;
+}
+
+static int pim_cmd_igmp_start(struct interface *ifp)
+{
+       struct pim_interface *pim_ifp;
+       uint8_t need_startup = 0;
+
+       pim_ifp = ifp->info;
+
+       if (!pim_ifp) {
+               (void)pim_if_new(ifp, true, false, false, false);
+               need_startup = 1;
+       } else {
+               if (!PIM_IF_TEST_IGMP(pim_ifp->options)) {
+                       PIM_IF_DO_IGMP(pim_ifp->options);
+                       need_startup = 1;
+               }
+       }
+
+       /* 'ip igmp' executed multiple times, with need_startup
+        * avoid multiple if add all and membership refresh
+        */
+       if (need_startup) {
+               pim_if_addr_add_all(ifp);
+               pim_if_membership_refresh(ifp);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * CLI reconfiguration affects the interface level (struct pim_interface).
+ * This function propagates the reconfiguration to every active socket
+ * for that interface.
+ */
+static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+
+       zassert(igmp);
+
+       /* other querier present? */
+
+       if (igmp->t_other_querier_timer)
+               return;
+
+       /* this is the querier */
+
+       zassert(igmp->interface);
+       zassert(igmp->interface->info);
+
+       ifp = igmp->interface;
+       pim_ifp = ifp->info;
+
+       if (PIM_DEBUG_IGMP_TRACE) {
+               char ifaddr_str[INET_ADDRSTRLEN];
+
+               pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
+                               sizeof(ifaddr_str));
+               zlog_debug("%s: Querier %s on %s reconfig query_interval=%d",
+                               __func__, ifaddr_str, ifp->name,
+                               pim_ifp->igmp_default_query_interval);
+       }
+
+       /*
+        * igmp_startup_mode_on() will reset QQI:
+
+        * igmp->querier_query_interval = pim_ifp->igmp_default_query_interval;
+        */
+       igmp_startup_mode_on(igmp);
+}
+
+static void igmp_sock_query_reschedule(struct igmp_sock *igmp)
+{
+       if (igmp->mtrace_only)
+               return;
+
+       if (igmp->t_igmp_query_timer) {
+               /* other querier present */
+               zassert(igmp->t_igmp_query_timer);
+               zassert(!igmp->t_other_querier_timer);
+
+               pim_igmp_general_query_off(igmp);
+               pim_igmp_general_query_on(igmp);
+
+               zassert(igmp->t_igmp_query_timer);
+               zassert(!igmp->t_other_querier_timer);
+       } else {
+               /* this is the querier */
+
+               zassert(!igmp->t_igmp_query_timer);
+               zassert(igmp->t_other_querier_timer);
+
+               pim_igmp_other_querier_timer_off(igmp);
+               pim_igmp_other_querier_timer_on(igmp);
+
+               zassert(!igmp->t_igmp_query_timer);
+               zassert(igmp->t_other_querier_timer);
+       }
+}
+
+static void change_query_interval(struct pim_interface *pim_ifp,
+               int query_interval)
+{
+       struct listnode *sock_node;
+       struct igmp_sock *igmp;
+
+       pim_ifp->igmp_default_query_interval = query_interval;
+
+       for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
+               igmp_sock_query_interval_reconfig(igmp);
+               igmp_sock_query_reschedule(igmp);
+       }
+}
+
+static void change_query_max_response_time(struct pim_interface *pim_ifp,
+               int query_max_response_time_dsec)
+{
+       struct listnode *sock_node;
+       struct igmp_sock *igmp;
+
+       pim_ifp->igmp_query_max_response_time_dsec =
+               query_max_response_time_dsec;
+
+       /*
+        * Below we modify socket/group/source timers in order to quickly
+        * reflect the change. Otherwise, those timers would args->eventually
+        * catch up.
+        */
+
+       /* scan all sockets */
+       for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
+               struct listnode *grp_node;
+               struct igmp_group *grp;
+
+               /* reschedule socket general query */
+               igmp_sock_query_reschedule(igmp);
+
+               /* scan socket groups */
+               for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grp_node,
+                                       grp)) {
+                       struct listnode *src_node;
+                       struct igmp_source *src;
+
+                       /* reset group timers for groups in EXCLUDE mode */
+                       if (grp->group_filtermode_isexcl)
+                               igmp_group_reset_gmi(grp);
+
+                       /* scan group sources */
+                       for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
+                                               src_node, src)) {
+
+                               /* reset source timers for sources with running
+                                * timers
+                                */
+                               if (src->t_source_timer)
+                                       igmp_source_reset_gmi(igmp, grp, src);
+                       }
+               }
+       }
+}
+
+int routing_control_plane_protocols_name_validate(
+       struct nb_cb_create_args *args)
+{
+       const char *name;
+
+       name = yang_dnode_get_string(args->dnode, "./name");
+       if (!strmatch(name, "pim")) {
+               snprintf(args->errmsg, args->errmsg_len,
+                               "pim supports only one instance with name pimd");
+               return NB_ERR_VALIDATION;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-pim:pim/packets
+ */
+int pim_packets_modify(struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               router->packet_process = yang_dnode_get_uint8(args->dnode,
+                               NULL);
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-pim:pim/join-prune-interval
+ */
+int pim_join_prune_interval_modify(struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               router->t_periodic = yang_dnode_get_uint16(args->dnode, NULL);
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-pim:pim/register-suppress-time
+ */
+int pim_register_suppress_time_modify(struct nb_cb_modify_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               pim->keep_alive_time = yang_dnode_get_uint16(args->dnode, NULL);
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/ecmp
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               pim->ecmp_enable = yang_dnode_get_bool(args->dnode, NULL);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/ecmp-rebalance
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_rebalance_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               pim->ecmp_rebalance_enable =
+                       yang_dnode_get_bool(args->dnode, NULL);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/keep-alive-timer
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_keep_alive_timer_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               pim->keep_alive_time = yang_dnode_get_uint16(args->dnode, NULL);
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/rp-keep-alive-timer
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_rp_keep_alive_timer_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               pim->rp_keep_alive_time = yang_dnode_get_uint16(args->dnode,
+                               NULL);
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_create(
+       struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               /* TODO: implement me. */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/send-v6-secondary
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               pim->send_v6_secondary = yang_dnode_get_bool(args->dnode, NULL);
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover
+ */
+void routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_apply_finish(
+       struct nb_cb_apply_finish_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       int spt_switch_action;
+       const char *prefix_list = NULL;
+
+       vrf = nb_running_get_entry(args->dnode, NULL, true);
+       pim = vrf->info;
+       spt_switch_action = yang_dnode_get_enum(args->dnode, "./spt-action");
+
+       switch (spt_switch_action) {
+       case PIM_SPT_INFINITY:
+               if (yang_dnode_exists(args->dnode,
+                                     "./spt-infinity-prefix-list"))
+                       prefix_list = yang_dnode_get_string(
+                               args->dnode, "./spt-infinity-prefix-list");
+
+               pim_cmd_spt_switchover(pim, PIM_SPT_INFINITY,
+                                       prefix_list);
+               break;
+       case PIM_SPT_IMMEDIATE:
+               pim_cmd_spt_switchover(pim, PIM_SPT_IMMEDIATE, NULL);
+       }
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover/spt-action
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_action_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover/spt-infinity-prefix-list
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ssm-prefix-list
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       const char *plist_name;
+       int result;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               plist_name = yang_dnode_get_string(args->dnode, NULL);
+               result = pim_ssm_cmd_worker(pim, plist_name, args->errmsg,
+                               args->errmsg_len);
+
+               if (result)
+                       return NB_ERR_INCONSISTENCY;
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       int result;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               result = pim_ssm_cmd_worker(pim, NULL, args->errmsg,
+                               args->errmsg_len);
+
+               if (result)
+                       return NB_ERR_INCONSISTENCY;
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ssm-pingd-source-ip
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_create(
+       struct nb_cb_create_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       int result;
+       struct ipaddr source_addr;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               yang_dnode_get_ip(&source_addr, args->dnode, NULL);
+               result = pim_ssmpingd_start(pim, source_addr.ip._v4_addr);
+               if (result) {
+                       char source_str[INET_ADDRSTRLEN];
+
+                       ipaddr2str(&source_addr, source_str,
+                                       sizeof(source_str));
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "%% Failure starting ssmpingd for source %s: %d",
+                                source_str, result);
+                       return NB_ERR_INCONSISTENCY;
+               }
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       int result;
+       struct ipaddr source_addr;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               yang_dnode_get_ip(&source_addr, args->dnode, NULL);
+               result = pim_ssmpingd_stop(pim, source_addr.ip._v4_addr);
+               if (result) {
+                       char source_str[INET_ADDRSTRLEN];
+
+                       ipaddr2str(&source_addr, source_str,
+                                  sizeof(source_str));
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "%% Failure stopping ssmpingd for source %s: %d",
+                                 source_str, result);
+                       return NB_ERR_INCONSISTENCY;
+               }
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create(
+       struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       const char *mesh_group_name;
+       int result;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               mesh_group_name = yang_dnode_get_string(args->dnode, ".");
+
+               result = ip_no_msdp_mesh_group_cmd_worker(pim, mesh_group_name,
+                               args->errmsg,
+                               args->errmsg_len);
+
+               if (result != PIM_MSDP_ERR_NONE)
+                       return NB_ERR_INCONSISTENCY;
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/mesh-group-name
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify(
+       struct nb_cb_modify_args *args)
+{
+       const char *mesh_group_name;
+       const char *mesh_group_name_old;
+       char xpath[XPATH_MAXLEN];
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               mesh_group_name = yang_dnode_get_string(args->dnode, ".");
+               yang_dnode_get_path(args->dnode, xpath, sizeof(xpath));
+
+               if (yang_dnode_exists(running_config->dnode, xpath) == false)
+                       break;
+
+               mesh_group_name_old = yang_dnode_get_string(
+                                       running_config->dnode,
+                                       xpath);
+               if (strcmp(mesh_group_name, mesh_group_name_old)) {
+                       /* currently only one mesh-group can exist at a time */
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "Only one mesh-group allowed currently");
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/member-ip
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create(
+       struct nb_cb_create_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       const char *mesh_group_name;
+       struct ipaddr mbr_ip;
+       enum pim_msdp_err result;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               mesh_group_name = yang_dnode_get_string(args->dnode,
+                               "../mesh-group-name");
+               yang_dnode_get_ip(&mbr_ip, args->dnode, NULL);
+
+               result = ip_msdp_mesh_group_member_cmd_worker(
+                               pim, mesh_group_name, mbr_ip.ip._v4_addr,
+                               args->errmsg, args->errmsg_len);
+
+               if (result != PIM_MSDP_ERR_NONE)
+                       return NB_ERR_INCONSISTENCY;
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       const char *mesh_group_name;
+       struct ipaddr mbr_ip;
+       enum pim_msdp_err result;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               mesh_group_name = yang_dnode_get_string(args->dnode,
+                               "../mesh-group-name");
+               yang_dnode_get_ip(&mbr_ip, args->dnode, NULL);
+
+               result = ip_no_msdp_mesh_group_member_cmd_worker(
+                               pim, mesh_group_name, mbr_ip.ip._v4_addr,
+                               args->errmsg, args->errmsg_len);
+
+               if (result != PIM_MSDP_ERR_NONE)
+                       return NB_ERR_INCONSISTENCY;
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/source-ip
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       const char *mesh_group_name;
+       struct ipaddr src_ip;
+       enum pim_msdp_err result;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               mesh_group_name = yang_dnode_get_string(args->dnode,
+                               "../mesh-group-name");
+               yang_dnode_get_ip(&src_ip, args->dnode, NULL);
+
+               result = ip_msdp_mesh_group_source_cmd_worker(
+                               pim, mesh_group_name, src_ip.ip._v4_addr,
+                               args->errmsg, args->errmsg_len);
+
+               if (result != PIM_MSDP_ERR_NONE)
+                       return NB_ERR_INCONSISTENCY;
+
+               break;
+       }
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       const char *mesh_group_name;
+       enum pim_msdp_err result;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               mesh_group_name = yang_dnode_get_string(args->dnode,
+                               "../mesh-group-name");
+
+               result = ip_no_msdp_mesh_group_source_cmd_worker(
+                               pim, mesh_group_name, args->errmsg,
+                               args->errmsg_len);
+
+               if (result != PIM_MSDP_ERR_NONE)
+                       return NB_ERR_INCONSISTENCY;
+
+               break;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create(
+       struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       int result;
+       struct pim_instance *pim;
+       struct ipaddr peer_ip;
+       struct vrf *vrf;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               yang_dnode_get_ip(&peer_ip, args->dnode, "./peer-ip");
+               result = ip_no_msdp_peer_cmd_worker(pim, peer_ip.ip._v4_addr,
+                               args->errmsg,
+                               args->errmsg_len);
+
+               if (result)
+                       return NB_ERR_INCONSISTENCY;
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/source-ip
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify(
+       struct nb_cb_modify_args *args)
+{
+       int result;
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       struct ipaddr peer_ip;
+       struct ipaddr source_ip;
+       const struct lyd_node *mesh_group_name_dnode;
+       const char *mesh_group_name;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               mesh_group_name_dnode =
+                       yang_dnode_get(args->dnode,
+                                       "../../msdp-mesh-group/mesh-group-name");
+               if (mesh_group_name_dnode) {
+                       mesh_group_name =
+                               yang_dnode_get_string(mesh_group_name_dnode,
+                                               ".");
+                       if (strcmp(mesh_group_name, "default")) {
+                               /* currently only one mesh-group can exist at a
+                                * time
+                                */
+                               snprintf(args->errmsg, args->errmsg_len,
+                                        "%% Only one mesh-group allowed currently");
+                               return NB_ERR_VALIDATION;
+                       }
+               }
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               yang_dnode_get_ip(&peer_ip, args->dnode, "../peer-ip");
+               yang_dnode_get_ip(&source_ip, args->dnode, NULL);
+
+               result = ip_msdp_peer_cmd_worker(pim, peer_ip.ip._v4_addr,
+                               source_ip.ip._v4_addr,
+                               args->errmsg,
+                               args->errmsg_len);
+
+               if (result)
+                       return NB_ERR_INCONSISTENCY;
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create(
+       struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct in_addr addr;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               addr.s_addr = 0;
+               pim_vxlan_mlag_update(true/*mlag_enable*/,
+                               false/*peer_state*/, MLAG_ROLE_NONE,
+                               NULL/*peerlink*/, &addr);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag
+ */
+void routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_apply_finish(
+       struct nb_cb_apply_finish_args *args)
+{
+       const char *ifname;
+       uint32_t role;
+       bool peer_state;
+       struct interface *ifp;
+       struct ipaddr reg_addr;
+
+       ifname = yang_dnode_get_string(args->dnode, "./peerlink-rif");
+       ifp = if_lookup_by_name(ifname, VRF_DEFAULT);
+       if (!ifp) {
+               snprintf(args->errmsg, args->errmsg_len,
+                        "No such interface name %s", ifname);
+               return;
+       }
+       role = yang_dnode_get_enum(args->dnode, "./my-role");
+       peer_state = yang_dnode_get_bool(args->dnode, "./peer-state");
+       yang_dnode_get_ip(&reg_addr, args->dnode, "./reg-address");
+
+       pim_vxlan_mlag_update(true, peer_state, role, ifp,
+                       &reg_addr.ip._v4_addr);
+}
+
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/peerlink-rif
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/reg-address
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/my-role
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_my_role_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/peer-state
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peer_state_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/register-accept-list
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       const char *plist;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               plist = yang_dnode_get_string(args->dnode, NULL);
+
+               XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist);
+               pim->register_plist = XSTRDUP(MTYPE_PIM_PLIST_NAME, plist);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+
+               XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist);
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim
+ */
+int lib_interface_pim_create(struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int lib_interface_pim_destroy(struct nb_cb_destroy_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               if (!pim_ifp)
+                       return NB_OK;
+
+               if (!pim_cmd_interface_delete(ifp)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "Unable to delete interface information %s",
+                                ifp->name);
+                       return NB_ERR_INCONSISTENCY;
+               }
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/pim-enable
+ */
+int lib_interface_pim_pim_enable_modify(struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+       int mcast_if_count;
+       const struct lyd_node *if_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if_dnode = yang_dnode_get_parent(args->dnode, "interface");
+               mcast_if_count =
+                       yang_get_list_elements_count(if_dnode);
+
+               /* Limiting mcast interfaces to number of VIFs */
+               if (mcast_if_count == MAXVIFS) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "Max multicast interfaces(%d) reached.",
+                                MAXVIFS);
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+
+               if (yang_dnode_get_bool(args->dnode, NULL)) {
+                       if (!pim_cmd_interface_add(ifp)) {
+                               snprintf(args->errmsg, args->errmsg_len,
+                                        "Could not enable PIM SM on interface %s",
+                                        ifp->name);
+                               return NB_ERR_INCONSISTENCY;
+                       }
+               } else {
+                       pim_ifp = ifp->info;
+                       if (!pim_ifp)
+                               return NB_ERR_INCONSISTENCY;
+
+                       if (!pim_cmd_interface_delete(ifp)) {
+                               snprintf(args->errmsg, args->errmsg_len,
+                                        "Unable to delete interface information");
+                               return NB_ERR_INCONSISTENCY;
+                       }
+               }
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/hello-interval
+ */
+int lib_interface_pim_hello_interval_modify(struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_ABORT:
+       case NB_EV_PREPARE:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               pim_ifp->pim_hello_period =
+                       yang_dnode_get_uint8(args->dnode, NULL);
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/hello-holdtime
+ */
+int lib_interface_pim_hello_holdtime_modify(struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_ABORT:
+       case NB_EV_PREPARE:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               pim_ifp->pim_default_holdtime =
+                       yang_dnode_get_uint8(args->dnode, NULL);
+               break;
+       }
+
+       return NB_OK;
+
+}
+
+int lib_interface_pim_hello_holdtime_destroy(struct nb_cb_destroy_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_ABORT:
+       case NB_EV_PREPARE:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               pim_ifp->pim_default_holdtime = -1;
+               break;
+       }
+
+       return NB_OK;
+}
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd
+ */
+int lib_interface_pim_bfd_create(struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int lib_interface_pim_bfd_destroy(struct nb_cb_destroy_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+       const struct lyd_node *if_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if_dnode = yang_dnode_get_parent(args->dnode, "interface");
+               if (!is_pim_interface(if_dnode)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "Pim not enabled on this interface");
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_ABORT:
+       case NB_EV_PREPARE:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode->parent, NULL, true);
+               pim_ifp = ifp->info;
+               if (pim_ifp->bfd_info) {
+                       pim_bfd_reg_dereg_all_nbr(ifp,
+                                       ZEBRA_BFD_DEST_DEREGISTER);
+                       bfd_info_free(&(pim_ifp->bfd_info));
+               }
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd
+ */
+void lib_interface_pim_bfd_apply_finish(struct nb_cb_apply_finish_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+       uint32_t min_rx;
+       uint32_t min_tx;
+       uint8_t detect_mult;
+
+       ifp = nb_running_get_entry(args->dnode->parent, NULL, true);
+       pim_ifp = ifp->info;
+
+       if (!pim_ifp) {
+               zlog_debug("Pim not enabled on this interface");
+               return;
+       }
+
+       min_rx = yang_dnode_get_uint16(args->dnode, "./min-rx-interval");
+       min_tx = yang_dnode_get_uint16(args->dnode, "./min-tx-interval");
+       detect_mult = yang_dnode_get_uint8(args->dnode, "./detect_mult");
+
+       if ((min_rx == BFD_DEF_MIN_RX) && (min_tx == BFD_DEF_MIN_TX)
+                       && (detect_mult == BFD_DEF_DETECT_MULT))
+               pim_bfd_if_param_set(ifp, min_rx, min_tx, detect_mult, 1);
+       else
+               pim_bfd_if_param_set(ifp, min_rx, min_tx, detect_mult, 0);
+
+       nb_running_set_entry(args->dnode, pim_ifp->bfd_info);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/min-rx-interval
+ */
+int lib_interface_pim_bfd_min_rx_interval_modify(struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/min-tx-interval
+ */
+int lib_interface_pim_bfd_min_tx_interval_modify(struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/detect_mult
+ */
+int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/bsm
+ */
+int lib_interface_pim_bsm_modify(struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               pim_ifp->bsm_enable = yang_dnode_get_bool(args->dnode, NULL);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/unicast-bsm
+ */
+int lib_interface_pim_unicast_bsm_modify(struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               pim_ifp->ucast_bsm_accept =
+                       yang_dnode_get_bool(args->dnode, NULL);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/active-active
+ */
+int lib_interface_pim_active_active_modify(struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               if (yang_dnode_get_bool(args->dnode, NULL)) {
+                       if (PIM_DEBUG_MLAG)
+                               zlog_debug(
+                                       "Configuring PIM active-active on Interface: %s",
+                                       ifp->name);
+                       pim_if_configure_mlag_dualactive(pim_ifp);
+               } else {
+                       if (PIM_DEBUG_MLAG)
+                               zlog_debug(
+                                       "UnConfiguring PIM active-active on Interface: %s",
+                                       ifp->name);
+                       pim_if_unconfigure_mlag_dualactive(pim_ifp);
+               }
+
+               break;
+       }
+
+       return NB_OK;
+
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/dr-priority
+ */
+int lib_interface_pim_dr_priority_modify(struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+       uint32_t old_dr_prio;
+       const struct lyd_node *if_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if_dnode = yang_dnode_get_parent(args->dnode, "interface");
+               if (!is_pim_interface(if_dnode)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                       "Pim not enabled on this interface");
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               old_dr_prio = pim_ifp->pim_dr_priority;
+               pim_ifp->pim_dr_priority = yang_dnode_get_uint32(args->dnode,
+                               NULL);
+
+               if (old_dr_prio != pim_ifp->pim_dr_priority) {
+                       pim_if_dr_election(ifp);
+                       pim_hello_restart_now(ifp);
+               }
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family
+ */
+int lib_interface_pim_address_family_create(struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int lib_interface_pim_address_family_destroy(struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/use-source
+ */
+int lib_interface_pim_address_family_use_source_modify(struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct ipaddr source_addr;
+       int result;
+       const struct lyd_node *if_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if_dnode = yang_dnode_get_parent(args->dnode, "interface");
+               if (!is_pim_interface(if_dnode)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                       "Pim not enabled on this interface");
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_ABORT:
+       case NB_EV_PREPARE:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               yang_dnode_get_ip(&source_addr, args->dnode, NULL);
+
+               result = interface_pim_use_src_cmd_worker(
+                               ifp, source_addr.ip._v4_addr,
+                               args->errmsg, args->errmsg_len);
+
+               if (result != PIM_SUCCESS)
+                       return NB_ERR_INCONSISTENCY;
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int lib_interface_pim_address_family_use_source_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct interface *ifp;
+       struct in_addr source_addr = {INADDR_ANY};
+       int result;
+       const struct lyd_node *if_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if_dnode = yang_dnode_get_parent(args->dnode, "interface");
+               if (!is_pim_interface(if_dnode)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                       "Pim not enabled on this interface");
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_ABORT:
+       case NB_EV_PREPARE:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+
+               result = interface_pim_use_src_cmd_worker(ifp, source_addr,
+                               args->errmsg,
+                               args->errmsg_len);
+
+               if (result != PIM_SUCCESS)
+                       return NB_ERR_INCONSISTENCY;
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/multicast-boundary-oil
+ */
+int lib_interface_pim_address_family_multicast_boundary_oil_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+       const char *plist;
+       const struct lyd_node *if_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if_dnode = yang_dnode_get_parent(args->dnode, "interface");
+               if (!is_pim_interface(if_dnode)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                       "Pim not enabled on this interface");
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_ABORT:
+       case NB_EV_PREPARE:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               plist = yang_dnode_get_string(args->dnode, NULL);
+
+               if (pim_ifp->boundary_oil_plist)
+                       XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
+
+               pim_ifp->boundary_oil_plist =
+                       XSTRDUP(MTYPE_PIM_INTERFACE, plist);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int lib_interface_pim_address_family_multicast_boundary_oil_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+       const struct lyd_node *if_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if_dnode = yang_dnode_get_parent(args->dnode, "interface");
+               if (!is_pim_interface(if_dnode)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "%% Enable PIM and/or IGMP on this interface first");
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_ABORT:
+       case NB_EV_PREPARE:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               if (pim_ifp->boundary_oil_plist)
+                       XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/mroute
+ */
+int lib_interface_pim_address_family_mroute_create(
+       struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int lib_interface_pim_address_family_mroute_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct pim_instance *pim;
+       struct pim_interface *pim_iifp;
+       struct interface *iif;
+       struct interface *oif;
+       const char *oifname;
+       struct ipaddr source_addr;
+       struct ipaddr group_addr;
+       const struct lyd_node *if_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if_dnode = yang_dnode_get_parent(args->dnode, "interface");
+               if (!is_pim_interface(if_dnode)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "%% Enable PIM and/or IGMP on this interface first");
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               iif = nb_running_get_entry(args->dnode, NULL, true);
+               pim_iifp = iif->info;
+               pim = pim_iifp->pim;
+
+               oifname = yang_dnode_get_string(args->dnode, "./oif");
+               oif = if_lookup_by_name(oifname, pim->vrf_id);
+
+               if (!oif) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                       "No such interface name %s",
+                                       oifname);
+                       return NB_ERR_INCONSISTENCY;
+               }
+
+               yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr");
+               yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr");
+
+               if (pim_static_del(pim, iif, oif, group_addr.ip._v4_addr,
+                                       source_addr.ip._v4_addr)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                       "Failed to remove static mroute");
+                       return NB_ERR_INCONSISTENCY;
+               }
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/mroute/oif
+ */
+int lib_interface_pim_address_family_mroute_oif_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct pim_instance *pim;
+       struct pim_interface *pim_iifp;
+       struct interface *iif;
+       struct interface *oif;
+       const char *oifname;
+       struct ipaddr source_addr;
+       struct ipaddr group_addr;
+       const struct lyd_node *if_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if_dnode = yang_dnode_get_parent(args->dnode, "interface");
+               if (!is_pim_interface(if_dnode)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "%% Enable PIM and/or IGMP on this interface first");
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               iif = nb_running_get_entry(args->dnode, NULL, true);
+               pim_iifp = iif->info;
+               pim = pim_iifp->pim;
+
+               oifname = yang_dnode_get_string(args->dnode, NULL);
+               oif = if_lookup_by_name(oifname, pim->vrf_id);
+
+               if (!oif) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "No such interface name %s",
+                                oifname);
+                       return NB_ERR_INCONSISTENCY;
+               }
+
+               yang_dnode_get_ip(&source_addr, args->dnode, "../source-addr");
+               yang_dnode_get_ip(&group_addr, args->dnode, "../group-addr");
+
+               if (pim_static_add(pim, iif, oif, group_addr.ip._v4_addr,
+                                  source_addr.ip._v4_addr)) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "Failed to add static mroute");
+                       return NB_ERR_INCONSISTENCY;
+               }
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int lib_interface_pim_address_family_mroute_oif_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/static-rp/rp-list
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_create(
+       struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       struct prefix group;
+       struct ipaddr rp_addr;
+       const char *plist;
+       int result = 0;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               yang_dnode_get_ip(&rp_addr, args->dnode, "./rp-address");
+
+               if (yang_dnode_get(args->dnode, "./group-list")) {
+                       yang_dnode_get_ipv4p(&group, args->dnode,
+                                       "./group-list");
+                       apply_mask_ipv4((struct prefix_ipv4 *)&group);
+                       result = pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr,
+                                       group, NULL, args->errmsg,
+                                       args->errmsg_len);
+               }
+
+               else if (yang_dnode_get(args->dnode, "./prefix-list")) {
+                       plist = yang_dnode_get_string(args->dnode,
+                                       "./prefix-list");
+                       if (!str2prefix("224.0.0.0/4", &group)) {
+                               flog_err(
+                                       EC_LIB_DEVELOPMENT,
+                                       "Unable to convert 224.0.0.0/4 to prefix");
+                               return NB_ERR_INCONSISTENCY;
+                       }
+
+                       result = pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr,
+                                       group, plist,
+                                       args->errmsg,
+                                       args->errmsg_len);
+               }
+
+               if (result)
+                       return NB_ERR_INCONSISTENCY;
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/static-rp/rp-list/group-list
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_create(
+       struct nb_cb_create_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       struct prefix group;
+       struct ipaddr rp_addr;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address");
+               yang_dnode_get_ipv4p(&group, args->dnode, NULL);
+               apply_mask_ipv4((struct prefix_ipv4 *)&group);
+
+               return pim_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group,
+                               NULL, args->errmsg, args->errmsg_len);
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       struct prefix group;
+       struct ipaddr rp_addr;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address");
+               yang_dnode_get_ipv4p(&group, args->dnode, NULL);
+               apply_mask_ipv4((struct prefix_ipv4 *)&group);
+
+               return pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group,
+                               NULL, args->errmsg,
+                               args->errmsg_len);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/static-rp/rp-list/prefix-list
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       struct prefix group;
+       struct ipaddr rp_addr;
+       const char *plist;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               plist = yang_dnode_get_string(args->dnode, NULL);
+               yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address");
+               if (!str2prefix("224.0.0.0/4", &group)) {
+                       flog_err(EC_LIB_DEVELOPMENT,
+                                "Unable to convert 224.0.0.0/4 to prefix");
+                       return NB_ERR_INCONSISTENCY;
+               }
+               return pim_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group,
+                               plist, args->errmsg, args->errmsg_len);
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+       struct prefix group;
+       struct ipaddr rp_addr;
+       const char *plist;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim = vrf->info;
+               yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address");
+               plist = yang_dnode_get_string(args->dnode, NULL);
+               if (!str2prefix("224.0.0.0/4", &group)) {
+                       flog_err(EC_LIB_DEVELOPMENT,
+                                "Unable to convert 224.0.0.0/4 to prefix");
+                       return NB_ERR_INCONSISTENCY;
+               }
+               return pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group,
+                               plist, args->errmsg,
+                               args->errmsg_len);
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-igmp:igmp
+ */
+int lib_interface_igmp_create(struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int lib_interface_igmp_destroy(struct nb_cb_destroy_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+
+               if (!pim_ifp)
+                       return NB_OK;
+
+               PIM_IF_DONT_IGMP(pim_ifp->options);
+
+               pim_if_membership_clear(ifp);
+
+               pim_if_addr_del_all_igmp(ifp);
+
+               if (!PIM_IF_TEST_PIM(pim_ifp->options))
+                       pim_if_delete(ifp);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-igmp:igmp/igmp-enable
+ */
+int lib_interface_igmp_igmp_enable_modify(struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       bool igmp_enable;
+       struct pim_interface *pim_ifp;
+       int mcast_if_count;
+       const char *ifp_name;
+       const struct lyd_node *if_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if_dnode = yang_dnode_get_parent(args->dnode, "interface");
+               ifp_name = yang_dnode_get_string(if_dnode, ".");
+               mcast_if_count =
+                       yang_get_list_elements_count(if_dnode);
+               /* Limiting mcast interfaces to number of VIFs */
+               if (mcast_if_count == MAXVIFS) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "Max multicast interfaces(%d) Reached. Could not enable IGMP on interface %s",
+                                MAXVIFS, ifp_name);
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               igmp_enable = yang_dnode_get_bool(args->dnode, NULL);
+
+               if (igmp_enable)
+                       return pim_cmd_igmp_start(ifp);
+
+               else {
+                       pim_ifp = ifp->info;
+
+                       if (!pim_ifp)
+                               return NB_ERR_INCONSISTENCY;
+
+                       PIM_IF_DONT_IGMP(pim_ifp->options);
+
+                       pim_if_membership_clear(ifp);
+
+                       pim_if_addr_del_all_igmp(ifp);
+
+                       if (!PIM_IF_TEST_PIM(pim_ifp->options))
+                               pim_if_delete(ifp);
+               }
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-igmp:igmp/version
+ */
+int lib_interface_igmp_version_modify(struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+       int igmp_version, old_version = 0;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+
+               if (!pim_ifp)
+                       return NB_ERR_INCONSISTENCY;
+
+               igmp_version = yang_dnode_get_uint8(args->dnode, NULL);
+               old_version = pim_ifp->igmp_version;
+               pim_ifp->igmp_version = igmp_version;
+
+               /* Current and new version is different refresh existing
+                * membership. Going from 3 -> 2 or 2 -> 3.
+                */
+               if (old_version != igmp_version)
+                       pim_if_membership_refresh(ifp);
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+int lib_interface_igmp_version_destroy(struct nb_cb_destroy_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-igmp:igmp/query-interval
+ */
+int lib_interface_igmp_query_interval_modify(struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+       int query_interval;
+       int query_interval_dsec;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               query_interval = yang_dnode_get_uint16(args->dnode, NULL);
+               query_interval_dsec = 10 * query_interval;
+               if (query_interval_dsec <=
+                               pim_ifp->igmp_query_max_response_time_dsec) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "Can't set general query interval %d dsec <= query max response time %d dsec.",
+                                query_interval_dsec,
+                                pim_ifp->igmp_query_max_response_time_dsec);
+                       return NB_ERR_INCONSISTENCY;
+               }
+               change_query_interval(pim_ifp, query_interval);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-igmp:igmp/query-max-response-time
+ */
+int lib_interface_igmp_query_max_response_time_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+       int query_max_response_time_dsec;
+       int default_query_interval_dsec;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               query_max_response_time_dsec =
+                       yang_dnode_get_uint8(args->dnode, NULL);
+               default_query_interval_dsec =
+                       10 * pim_ifp->igmp_default_query_interval;
+
+               if (query_max_response_time_dsec
+                       >= default_query_interval_dsec) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "Can't set query max response time %d sec >= general query interval %d sec",
+                                query_max_response_time_dsec,
+                                pim_ifp->igmp_default_query_interval);
+                       return NB_ERR_INCONSISTENCY;
+               }
+
+               change_query_max_response_time(pim_ifp,
+                               query_max_response_time_dsec);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-igmp:igmp/last-member-query-interval
+ */
+int lib_interface_igmp_last_member_query_interval_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+       int last_member_query_interval;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               last_member_query_interval = yang_dnode_get_uint8(args->dnode,
+                               NULL);
+               pim_ifp->igmp_specific_query_max_response_time_dsec =
+                       last_member_query_interval;
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-igmp:igmp/robustness-variable
+ */
+int lib_interface_igmp_robustness_variable_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+       int last_member_query_count;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               last_member_query_count = yang_dnode_get_uint8(args->dnode,
+                               NULL);
+               pim_ifp->igmp_last_member_query_count = last_member_query_count;
+
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-igmp:igmp/address-family
+ */
+int lib_interface_igmp_address_family_create(struct nb_cb_create_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int lib_interface_igmp_address_family_destroy(struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-igmp:igmp/address-family/static-group
+ */
+int lib_interface_igmp_address_family_static_group_create(
+       struct nb_cb_create_args *args)
+{
+       struct interface *ifp;
+       struct ipaddr source_addr;
+       struct ipaddr group_addr;
+       int result;
+       const char *ifp_name;
+       const struct lyd_node *if_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if_dnode =  yang_dnode_get_parent(args->dnode, "interface");
+               if (!is_pim_interface(if_dnode)) {
+                       ifp_name = yang_dnode_get_string(if_dnode, ".");
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "multicast not enabled on interface %s",
+                                ifp_name);
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr");
+               yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr");
+
+               result = pim_if_igmp_join_add(ifp, group_addr.ip._v4_addr,
+                               source_addr.ip._v4_addr);
+               if (result) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "Failure joining IGMP group");
+                       return NB_ERR_INCONSISTENCY;
+               }
+       }
+
+       return NB_OK;
+}
+
+int lib_interface_igmp_address_family_static_group_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct interface *ifp;
+       struct ipaddr source_addr;
+       struct ipaddr group_addr;
+       int result;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr");
+               yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr");
+
+               result = pim_if_igmp_join_del(ifp, group_addr.ip._v4_addr,
+                               source_addr.ip._v4_addr);
+
+               if (result) {
+                       char src_str[INET_ADDRSTRLEN];
+                       char grp_str[INET_ADDRSTRLEN];
+
+                       ipaddr2str(&source_addr, src_str, sizeof(src_str));
+                       ipaddr2str(&group_addr, grp_str, sizeof(grp_str));
+
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "%% Failure leaving IGMP group %s %s on interface %s: %d",
+                                src_str, grp_str, ifp->name, result);
+
+                       return NB_ERR_INCONSISTENCY;
+               }
+
+               break;
+       }
+
+       return NB_OK;
+}
index f691e8b75592d541316cfc65673dcfca718b0c0a..68e0a45690e82c7d8cbaaa973b40a43aa3759d46 100644 (file)
@@ -55,7 +55,7 @@ void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
 
        p = &(pnc->rpf.rpf_addr);
        ret = zclient_send_rnh(zclient, command, p, false, pim->vrf_id);
-       if (ret < 0)
+       if (ret == ZCLIENT_SEND_FAILURE)
                zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
 
        if (PIM_DEBUG_PIM_NHT)
index 7246482f022f4601b79c841e6eb69b6f78a25fac..301a27001f93f7c828690885d4816e13700a3d32 100644 (file)
@@ -271,7 +271,7 @@ struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
  *
  * This is a placeholder function for now.
  */
-static void pim_rp_refresh_group_to_rp_mapping(struct pim_instance *pim)
+void pim_rp_refresh_group_to_rp_mapping(struct pim_instance *pim)
 {
        pim_msdp_i_am_rp_changed(pim);
        pim_upstream_reeval_use_rpt(pim);
@@ -394,39 +394,6 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up)
        pim_zebra_update_all_interfaces(pim);
 }
 
-int pim_rp_new_config(struct pim_instance *pim, const char *rp,
-                     const char *group_range, const char *plist)
-{
-       int result = 0;
-       struct prefix group;
-       struct in_addr rp_addr;
-
-       if (group_range == NULL)
-               result = str2prefix("224.0.0.0/4", &group);
-       else {
-               result = str2prefix(group_range, &group);
-               if (result) {
-                       struct prefix temp;
-
-                       prefix_copy(&temp, &group);
-                       apply_mask(&temp);
-                       if (!prefix_same(&group, &temp))
-                               return PIM_GROUP_BAD_ADDR_MASK_COMBO;
-               }
-       }
-
-       if (!result)
-               return PIM_GROUP_BAD_ADDRESS;
-
-       result = inet_pton(AF_INET, rp, &rp_addr);
-
-       if (result <= 0)
-               return PIM_RP_BAD_ADDRESS;
-
-       result = pim_rp_new(pim, rp_addr, group, plist, RP_SRC_STATIC);
-       return result;
-}
-
 int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr,
               struct prefix group, const char *plist,
               enum rp_source rp_src_flag)
@@ -1352,7 +1319,7 @@ void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr)
                        continue;
 
                for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) {
-                       if (nh_node->gate.ipv4.s_addr != 0)
+                       if (nh_node->gate.ipv4.s_addr != INADDR_ANY)
                                continue;
 
                        struct interface *ifp1 = if_lookup_by_index(
index 6dc26c07a95ca63e362a7a28f6ef3c26a883af2f..dd7cd5d75e35504a7c57851355042be7f5d07aab 100644 (file)
@@ -46,8 +46,6 @@ void pim_rp_free(struct pim_instance *pim);
 
 void pim_rp_list_hash_clean(void *data);
 
-int pim_rp_new_config(struct pim_instance *pim, const char *rp,
-                     const char *group, const char *plist);
 int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr,
               struct prefix group, const char *plist,
               enum rp_source rp_src_flag);
@@ -88,4 +86,5 @@ int pim_rp_list_cmp(void *v1, void *v2);
 struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
                                        const struct prefix *group);
 void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up);
+void pim_rp_refresh_group_to_rp_mapping(struct pim_instance *pim);
 #endif
index 91c9b5b9337ec48a35d6ce97a6d8bae41919e745..63a9a0065941a582d4d72754e5035aebd491e890 100644 (file)
@@ -345,7 +345,7 @@ int pim_static_write_mroute(struct pim_instance *pim, struct vty *vty,
                                        struct interface *oifp =
                                                pim_if_find_by_vif_index(pim,
                                                                         i);
-                                       if (sroute->source.s_addr == 0)
+                                       if (sroute->source.s_addr == INADDR_ANY)
                                                vty_out(vty,
                                                        " ip mroute %s %s\n",
                                                        oifp->name, gbuf);
index d95b092d947a16f01c74d1f0a0d540d95897abac..9899172e6cefca138b8cdcaef8ee48bec42b59a7 100644 (file)
@@ -749,6 +749,13 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
                bool send_xg_jp = false;
 
                forward_off(up);
+               /*
+                * RFC 4601 Sec 4.5.7:
+                * JoinDesired(S,G) -> False, set SPTbit to false.
+                */
+               if (up->sg.src.s_addr != INADDR_ANY)
+                       up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
+
                if (old_state == PIM_UPSTREAM_JOINED)
                        pim_msdp_up_join_state_changed(pim, up);
 
diff --git a/pimd/pim_version.c b/pimd/pim_version.c
deleted file mode 100644 (file)
index 439f745..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * PIM for Quagga
- * Copyright (C) 2008  Everton da Silva Marques
- *
- * 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 "pim_version.h"
-
-const char *const PIMD_VERSION = PIMD_VERSION_STR;
diff --git a/pimd/pim_version.h b/pimd/pim_version.h
deleted file mode 100644 (file)
index c45d01a..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * PIM for Quagga
- * Copyright (C) 2008  Everton da Silva Marques
- *
- * 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_VERSION_H
-#define PIM_VERSION_H
-
-#define PIMD_VERSION_STR "0.166"
-
-const char *const PIMD_VERSION;
-
-#endif /* PIM_VERSION_H */
index 1f2ca11db3bd373cc74620279114221d2a9b1bc3..57a0c691661a18664aa0a2ec4cab1242e064e5ed 100644 (file)
@@ -275,6 +275,13 @@ int pim_interface_config_write(struct vty *vty)
                        continue;
 
                FOR_ALL_INTERFACES (pim->vrf, ifp) {
+                       /* pim is enabled internally/implicitly on the vxlan
+                        * termination device ipmr-lo. skip displaying that
+                        * config to avoid confusion
+                        */
+                       if (pim_vxlan_is_term_dev_cfg(pim, ifp))
+                               continue;
+
                        /* IF name */
                        if (vrf->vrf_id == VRF_DEFAULT)
                                vty_frame(vty, "interface %s\n", ifp->name);
index 18f1b74175977191d843da273ff733e659b59352..ce9054cd267089d203790c6b50957d486433a8f0 100644 (file)
@@ -109,7 +109,7 @@ struct pim_vxlan {
  */
 static inline bool pim_vxlan_is_orig_mroute(struct pim_vxlan_sg *vxlan_sg)
 {
-       return (vxlan_sg->sg.src.s_addr != 0);
+       return (vxlan_sg->sg.src.s_addr != INADDR_ANY);
 }
 
 static inline bool pim_vxlan_is_local_sip(struct pim_upstream *up)
index dc4c621e9c452bbd27b6dbc9588763e67dfa3f8c..05c9af8734b73071c46f773909916d8aad7466c6 100644 (file)
@@ -61,7 +61,7 @@ static int zclient_lookup_connect(struct thread *t)
                zlookup->fail = 0; /* reset counter on connection */
        }
 
-       if (zclient_send_hello(zlookup) < 0) {
+       if (zclient_send_hello(zlookup) == ZCLIENT_SEND_FAILURE) {
                if (close(zlookup->sock)) {
                        zlog_warn("%s: closing fd=%d: errno=%d %s", __func__,
                                  zlookup->sock, errno, safe_strerror(errno));
index 8952d15aaaacdfdaf8ece90f74a6614431110a25..717f4782f8bc3ca40454050d4445a0f0eae89410 100644 (file)
@@ -41,6 +41,8 @@ pimd_libpim_a_SOURCES = \
        pimd/pim_msdp_packet.c \
        pimd/pim_msdp_socket.c \
        pimd/pim_msg.c \
+       pimd/pim_nb.c \
+       pimd/pim_nb_config.c \
        pimd/pim_neighbor.c \
        pimd/pim_nht.c \
        pimd/pim_oil.c \
@@ -59,13 +61,15 @@ pimd_libpim_a_SOURCES = \
        pimd/pim_tlv.c \
        pimd/pim_upstream.c \
        pimd/pim_util.c \
-       pimd/pim_version.c \
        pimd/pim_vty.c \
        pimd/pim_zebra.c \
        pimd/pim_zlookup.c \
        pimd/pim_vxlan.c \
        pimd/pim_zpthread.c \
        pimd/pimd.c \
+       yang/frr-pim.yang.c \
+       yang/frr-pim-rp.yang.c \
+       yang/frr-igmp.yang.c \
        # end
 
 noinst_HEADERS += \
@@ -96,6 +100,7 @@ noinst_HEADERS += \
        pimd/pim_msdp_packet.h \
        pimd/pim_msdp_socket.h \
        pimd/pim_msg.h \
+       pimd/pim_nb.h \
        pimd/pim_neighbor.h \
        pimd/pim_nht.h \
        pimd/pim_oil.h \
@@ -113,7 +118,6 @@ noinst_HEADERS += \
        pimd/pim_tlv.h \
        pimd/pim_upstream.h \
        pimd/pim_util.h \
-       pimd/pim_version.h \
        pimd/pim_vty.h \
        pimd/pim_zebra.h \
        pimd/pim_zlookup.h \
index e72d2e3f36264729af55ff3a39ea9fca4465da6f..02c272f47c794b066583af011571737c21d97c5b 100644 (file)
@@ -27,6 +27,7 @@
 %{!?with_vrrpd:         %global  with_vrrpd         1 }
 %{!?with_rtadv:         %global  with_rtadv         1 }
 %{!?with_watchfrr:      %global  with_watchfrr      1 }
+%{!?with_pathd:         %global  with_pathd         1 }
 
 # user and group
 %{!?frr_user:           %global  frr_user           frr }
@@ -87,7 +88,7 @@
 %{!?frr_gid:            %global  frr_gid            92 }
 %{!?vty_gid:            %global  vty_gid            85 }
 
-%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd staticd bfdd fabricd
+%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd staticd bfdd fabricd pathd
 
 %if %{with_ldpd}
     %define daemon_ldpd ldpd
     %define daemon_bfdd ""
 %endif
 
-%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd} %{daemon_bfdd} %{daemon_vrrpd}
+%if %{with_pathd}
+    %define daemon_pathd pathd
+%else
+    %define daemon_pathd ""
+%endif
+
+%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd} %{daemon_bfdd} %{daemon_vrrpd} %{daemon_pathd}
 
 #release sub-revision (the two digits after the CONFDATE)
 %{!?release_rev:        %global  release_rev        01 }
@@ -397,6 +404,11 @@ routing state through standard SNMP MIBs.
     --enable-bfdd \
 %else
     --disable-bfdd \
+%endif
+%if %{with_pathd}
+    --enable-pathd \
+%else
+    --disable-pathd \
 %endif
     --enable-snmp
     # end
@@ -526,6 +538,9 @@ zebra_spec_add_service fabricd      2618/tcp "Fabricd vty"
 %if %{with_vrrpd}
     zebra_spec_add_service vrrpd    2619/tcp "VRRPd vty"
 %endif
+%if %{with_pathd}
+    zebra_spec_add_service pathd    2620/tcp "Pathd vty"
+%endif
 
 %if "%{initsystem}" == "systemd"
     for daemon in %all_daemons ; do
@@ -681,6 +696,9 @@ fi
 %if %{with_bfdd}
     %{_sbindir}/bfdd
 %endif
+%if %{with_pathd}
+    %{_sbindir}/pathd
+%endif
 %{_libdir}/libfrr.so*
 %{_libdir}/libfrrcares*
 %{_libdir}/libfrrospf*
@@ -747,6 +765,10 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons
 %{_includedir}/%{name}/*.h
 %dir %{_includedir}/%{name}/ospfd
 %{_includedir}/%{name}/ospfd/*.h
+%if %{with_bfdd}
+    %dir %{_includedir}/%{name}/bfdd
+    %{_includedir}/%{name}/bfdd/bfddp_packet.h
+%endif
 %if %{with_ospfapi}
     %dir %{_includedir}/%{name}/ospfapi
     %{_includedir}/%{name}/ospfapi/*.h
@@ -794,6 +816,9 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons
 -    migrate route-maps to use northbound interface
 - plus countless bug fixes and other improvements
 
+* Mon Jun 15 2020 Sascha Kattelmann <sascha@netdef.org>
+- Add Pathd support
+
 * Wed May 06 2020 David Lamparter <equinox@opensourcerouting.org> - 7.3.1
 - upstream 7.3.1
 
index 0cec847f057c643fee83700a3f38b7367fa5b027..82dd401f96031f7203e63f87536a98b4b1a9172a 100644 (file)
@@ -495,7 +495,7 @@ static void rip_rte_process(struct rte *rte, struct sockaddr_in *from,
                rte->metric = RIP_METRIC_INFINITY;
 
        /* Set nexthop pointer. */
-       if (rte->nexthop.s_addr == 0)
+       if (rte->nexthop.s_addr == INADDR_ANY)
                nexthop = &from->sin_addr;
        else
                nexthop = &rte->nexthop;
@@ -592,7 +592,7 @@ static void rip_rte_process(struct rte *rte, struct sockaddr_in *from,
                        /* Only routes directly connected to an interface
                         * (nexthop == 0)
                         * may have a valid NULL distance */
-                       if (rinfo->nh.gate.ipv4.s_addr != 0)
+                       if (rinfo->nh.gate.ipv4.s_addr != INADDR_ANY)
                                old_dist = old_dist
                                                   ? old_dist
                                                   : ZEBRA_RIP_DISTANCE_DEFAULT;
@@ -2156,7 +2156,7 @@ void rip_output_process(struct connected *ifc, struct sockaddr_in *to,
                                        memcpy(&classfull, &rp->p,
                                               sizeof(struct prefix_ipv4));
                                        apply_classful_mask_ipv4(&classfull);
-                                       if (rp->p.u.prefix4.s_addr != 0
+                                       if (rp->p.u.prefix4.s_addr != INADDR_ANY
                                            && classfull.prefixlen
                                                       != rp->p.prefixlen)
                                                continue;
index 0bd47454a9250c254d490db553c27ee9edbf983c..52561fd451562798168bac6f16a7b949efc1bf02 100644 (file)
@@ -45,6 +45,8 @@ struct sharp_routes {
 
        struct timeval t_start;
        struct timeval t_end;
+
+       char opaque[ZAPI_MESSAGE_OPAQUE_LENGTH];
 };
 
 struct sharp_global {
index 4cd92c7f3d72688f9f87d169a8587e71446cab3c..fe7f9851f9015d4e40df28083edd3bef46d271c9 100644 (file)
@@ -139,6 +139,16 @@ static void sharp_global_init(void)
        sg.nhs = list_new();
 }
 
+static void sharp_start_configuration(void)
+{
+       zlog_debug("Configuration has started to be read");
+}
+
+static void sharp_end_configuration(void)
+{
+       zlog_debug("Configuration has finished being read");
+}
+
 int main(int argc, char **argv, char **envp)
 {
        frr_preinit(&sharpd_di, argc, argv);
@@ -163,6 +173,8 @@ int main(int argc, char **argv, char **envp)
 
        master = frr_init();
 
+       cmd_init_config_callbacks(sharp_start_configuration,
+                                 sharp_end_configuration);
        sharp_global_init();
 
        sharp_nhgroup_init();
index 45c0799fa77700a606611efd3c0dafeeb2797831..940415b067bb5263619713653415ded7602e3b0a 100644 (file)
@@ -163,7 +163,7 @@ DEFPY (install_routes,
          <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|\
           nexthop-group NHGNAME$nexthop_group>\
          [backup$backup <A.B.C.D$backup_nexthop4|X:X::X:X$backup_nexthop6>] \
-         (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]",
+         (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt] [opaque WORD]",
        "Sharp routing Protocol\n"
        "install some routes\n"
        "Routes to install\n"
@@ -183,7 +183,9 @@ DEFPY (install_routes,
        "Instance to use\n"
        "Instance\n"
        "Should we repeat this command\n"
-       "How many times to repeat this command\n")
+       "How many times to repeat this command\n"
+       "What opaque data to send down\n"
+       "The opaque data\n")
 {
        struct vrf *vrf;
        struct prefix prefix;
@@ -205,7 +207,7 @@ DEFPY (install_routes,
        memset(&sg.r.backup_nhop, 0, sizeof(sg.r.nhop));
        memset(&sg.r.backup_nhop_group, 0, sizeof(sg.r.nhop_group));
 
-       if (start4.s_addr != 0) {
+       if (start4.s_addr != INADDR_ANY) {
                prefix.family = AF_INET;
                prefix.prefixlen = 32;
                prefix.u.prefix4 = start4;
@@ -292,12 +294,17 @@ DEFPY (install_routes,
                sg.r.backup_nhop_group.nexthop = &sg.r.backup_nhop;
        }
 
+       if (opaque)
+               strlcpy(sg.r.opaque, opaque, ZAPI_MESSAGE_OPAQUE_LENGTH);
+       else
+               sg.r.opaque[0] = '\0';
+
        sg.r.inst = instance;
        sg.r.vrf_id = vrf->vrf_id;
        rts = routes;
        sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst, nhgid,
                                    &sg.r.nhop_group, &sg.r.backup_nhop_group,
-                                   rts);
+                                   rts, sg.r.opaque);
 
        return CMD_SUCCESS;
 }
@@ -355,7 +362,7 @@ DEFPY (remove_routes,
 
        memset(&prefix, 0, sizeof(prefix));
 
-       if (start4.s_addr != 0) {
+       if (start4.s_addr != INADDR_ANY) {
                prefix.family = AF_INET;
                prefix.prefixlen = 32;
                prefix.u.prefix4 = start4;
@@ -665,7 +672,7 @@ DEFPY (neigh_discover,
 
        memset(&prefix, 0, sizeof(prefix));
 
-       if (dst4.s_addr != 0) {
+       if (dst4.s_addr != INADDR_ANY) {
                prefix.family = AF_INET;
                prefix.prefixlen = 32;
                prefix.u.prefix4 = dst4;
index 7a335fca3b67a19b9dfa0f62a7f0cf9e933122c6..4445bc0132ebcb7d4722dcf18fce6f9470544fa4 100644 (file)
@@ -211,66 +211,226 @@ int sharp_install_lsps_helper(bool install_p, bool update_p,
                cmd = ZEBRA_MPLS_LABELS_DELETE;
        }
 
-       ret = zebra_send_mpls_labels(zclient, cmd, &zl);
+       if (zebra_send_mpls_labels(zclient, cmd, &zl) == ZCLIENT_SEND_FAILURE)
+               return -1;
 
-       return ret;
+       return 0;
 }
 
-void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
-                                uint8_t instance, uint32_t nhgid,
-                                const struct nexthop_group *nhg,
-                                const struct nexthop_group *backup_nhg,
-                                uint32_t routes)
+enum where_to_restart {
+       SHARP_INSTALL_ROUTES_RESTART,
+       SHARP_DELETE_ROUTES_RESTART,
+};
+
+struct buffer_delay {
+       struct prefix p;
+       uint32_t count;
+       uint32_t routes;
+       vrf_id_t vrf_id;
+       uint8_t instance;
+       uint32_t nhgid;
+       const struct nexthop_group *nhg;
+       const struct nexthop_group *backup_nhg;
+       enum where_to_restart restart;
+       char *opaque;
+} wb;
+
+/*
+ * route_add - Encodes a route to zebra
+ *
+ * This function returns true when the route was buffered
+ * by the underlying stream system
+ */
+static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance,
+                     uint32_t nhgid, const struct nexthop_group *nhg,
+                     const struct nexthop_group *backup_nhg, char *opaque)
+{
+       struct zapi_route api;
+       struct zapi_nexthop *api_nh;
+       struct nexthop *nh;
+       int i = 0;
+
+       memset(&api, 0, sizeof(api));
+       api.vrf_id = vrf_id;
+       api.type = ZEBRA_ROUTE_SHARP;
+       api.instance = instance;
+       api.safi = SAFI_UNICAST;
+       memcpy(&api.prefix, p, sizeof(*p));
+
+       SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
+       SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+
+       /* Only send via ID if nhgroup has been successfully installed */
+       if (nhgid && sharp_nhgroup_id_is_installed(nhgid)) {
+               SET_FLAG(api.message, ZAPI_MESSAGE_NHG);
+               api.nhgid = nhgid;
+       } else {
+               for (ALL_NEXTHOPS_PTR(nhg, nh)) {
+                       api_nh = &api.nexthops[i];
+
+                       zapi_nexthop_from_nexthop(api_nh, nh);
+
+                       i++;
+               }
+               api.nexthop_num = i;
+       }
+
+       /* Include backup nexthops, if present */
+       if (backup_nhg && backup_nhg->nexthop) {
+               SET_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS);
+
+               i = 0;
+               for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) {
+                       api_nh = &api.backup_nexthops[i];
+
+                       zapi_backup_nexthop_from_nexthop(api_nh, nh);
+
+                       i++;
+               }
+
+               api.backup_nexthop_num = i;
+       }
+
+       if (strlen(opaque)) {
+               SET_FLAG(api.message, ZAPI_MESSAGE_OPAQUE);
+               api.opaque.length = strlen(opaque) + 1;
+               assert(api.opaque.length <= ZAPI_MESSAGE_OPAQUE_LENGTH);
+               memcpy(api.opaque.data, opaque, api.opaque.length);
+       }
+
+       if (zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api)
+           == ZCLIENT_SEND_BUFFERED)
+               return true;
+       else
+               return false;
+}
+
+/*
+ * route_delete - Encodes a route for deletion to zebra
+ *
+ * This function returns true when the route sent was
+ * buffered by the underlying stream system.
+ */
+static bool route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance)
+{
+       struct zapi_route api;
+
+       memset(&api, 0, sizeof(api));
+       api.vrf_id = vrf_id;
+       api.type = ZEBRA_ROUTE_SHARP;
+       api.safi = SAFI_UNICAST;
+       api.instance = instance;
+       memcpy(&api.prefix, p, sizeof(*p));
+
+       if (zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api)
+           == ZCLIENT_SEND_BUFFERED)
+               return true;
+       else
+               return false;
+}
+
+static void sharp_install_routes_restart(struct prefix *p, uint32_t count,
+                                        vrf_id_t vrf_id, uint8_t instance,
+                                        uint32_t nhgid,
+                                        const struct nexthop_group *nhg,
+                                        const struct nexthop_group *backup_nhg,
+                                        uint32_t routes, char *opaque)
 {
        uint32_t temp, i;
        bool v4 = false;
 
-       zlog_debug("Inserting %u routes", routes);
-
        if (p->family == AF_INET) {
                v4 = true;
                temp = ntohl(p->u.prefix4.s_addr);
        } else
                temp = ntohl(p->u.val32[3]);
 
-       /* Only use backup route/nexthops if present */
-       if (backup_nhg && (backup_nhg->nexthop == NULL))
-               backup_nhg = NULL;
-
-       monotime(&sg.r.t_start);
-       for (i = 0; i < routes; i++) {
-               route_add(p, vrf_id, (uint8_t)instance, nhgid, nhg, backup_nhg);
+       for (i = count; i < routes; i++) {
+               bool buffered = route_add(p, vrf_id, (uint8_t)instance, nhgid,
+                                         nhg, backup_nhg, opaque);
                if (v4)
                        p->u.prefix4.s_addr = htonl(++temp);
                else
                        p->u.val32[3] = htonl(++temp);
+
+               if (buffered) {
+                       wb.p = *p;
+                       wb.count = i+1;
+                       wb.routes = routes;
+                       wb.vrf_id = vrf_id;
+                       wb.instance = instance;
+                       wb.nhgid = nhgid;
+                       wb.nhg = nhg;
+                       wb.backup_nhg = backup_nhg;
+                       wb.opaque = opaque;
+                       wb.restart = SHARP_INSTALL_ROUTES_RESTART;
+
+                       return;
+               }
        }
 }
 
-void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id,
-                               uint8_t instance, uint32_t routes)
+void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
+                                uint8_t instance, uint32_t nhgid,
+                                const struct nexthop_group *nhg,
+                                const struct nexthop_group *backup_nhg,
+                                uint32_t routes, char *opaque)
+{
+       zlog_debug("Inserting %u routes", routes);
+
+       /* Only use backup route/nexthops if present */
+       if (backup_nhg && (backup_nhg->nexthop == NULL))
+               backup_nhg = NULL;
+
+       monotime(&sg.r.t_start);
+       sharp_install_routes_restart(p, 0, vrf_id, instance, nhgid, nhg,
+                                    backup_nhg, routes, opaque);
+}
+
+static void sharp_remove_routes_restart(struct prefix *p, uint32_t count,
+                                       vrf_id_t vrf_id, uint8_t instance,
+                                       uint32_t routes)
 {
        uint32_t temp, i;
        bool v4 = false;
 
-       zlog_debug("Removing %u routes", routes);
-
        if (p->family == AF_INET) {
                v4 = true;
                temp = ntohl(p->u.prefix4.s_addr);
        } else
                temp = ntohl(p->u.val32[3]);
 
-       monotime(&sg.r.t_start);
-       for (i = 0; i < routes; i++) {
-               route_delete(p, vrf_id, (uint8_t)instance);
+       for (i = count; i < routes; i++) {
+               bool buffered = route_delete(p, vrf_id, (uint8_t)instance);
+
                if (v4)
                        p->u.prefix4.s_addr = htonl(++temp);
                else
                        p->u.val32[3] = htonl(++temp);
+
+               if (buffered) {
+                       wb.p = *p;
+                       wb.count = i + 1;
+                       wb.vrf_id = vrf_id;
+                       wb.instance = instance;
+                       wb.routes = routes;
+                       wb.restart = SHARP_DELETE_ROUTES_RESTART;
+
+                       return;
+               }
        }
 }
 
+void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id,
+                               uint8_t instance, uint32_t routes)
+{
+       zlog_debug("Removing %u routes", routes);
+
+       monotime(&sg.r.t_start);
+
+       sharp_remove_routes_restart(p, 0, vrf_id, instance, routes);
+}
+
 static void handle_repeated(bool installed)
 {
        struct prefix p = sg.r.orig_prefix;
@@ -290,7 +450,22 @@ static void handle_repeated(bool installed)
                sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst,
                                            sg.r.nhgid, &sg.r.nhop_group,
                                            &sg.r.backup_nhop_group,
-                                           sg.r.total_routes);
+                                           sg.r.total_routes, sg.r.opaque);
+       }
+}
+
+static void sharp_zclient_buffer_ready(void)
+{
+       switch (wb.restart) {
+       case SHARP_INSTALL_ROUTES_RESTART:
+               sharp_install_routes_restart(
+                       &wb.p, wb.count, wb.vrf_id, wb.instance, wb.nhgid,
+                       wb.nhg, wb.backup_nhg, wb.routes, wb.opaque);
+               return;
+       case SHARP_DELETE_ROUTES_RESTART:
+               sharp_remove_routes_restart(&wb.p, wb.count, wb.vrf_id,
+                                           wb.instance, wb.routes);
+               return;
        }
 }
 
@@ -408,74 +583,6 @@ void nhg_del(uint32_t id)
        zclient_nhg_send(zclient, ZEBRA_NHG_DEL, &api_nhg);
 }
 
-void route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance,
-              uint32_t nhgid, const struct nexthop_group *nhg,
-              const struct nexthop_group *backup_nhg)
-{
-       struct zapi_route api;
-       struct zapi_nexthop *api_nh;
-       struct nexthop *nh;
-       int i = 0;
-
-       memset(&api, 0, sizeof(api));
-       api.vrf_id = vrf_id;
-       api.type = ZEBRA_ROUTE_SHARP;
-       api.instance = instance;
-       api.safi = SAFI_UNICAST;
-       memcpy(&api.prefix, p, sizeof(*p));
-
-       SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
-       SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
-
-       /* Only send via ID if nhgroup has been successfully installed */
-       if (nhgid && sharp_nhgroup_id_is_installed(nhgid)) {
-               SET_FLAG(api.message, ZAPI_MESSAGE_NHG);
-               api.nhgid = nhgid;
-       } else {
-               for (ALL_NEXTHOPS_PTR(nhg, nh)) {
-                       api_nh = &api.nexthops[i];
-
-                       zapi_nexthop_from_nexthop(api_nh, nh);
-
-                       i++;
-               }
-               api.nexthop_num = i;
-       }
-
-       /* Include backup nexthops, if present */
-       if (backup_nhg && backup_nhg->nexthop) {
-               SET_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS);
-
-               i = 0;
-               for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) {
-                       api_nh = &api.backup_nexthops[i];
-
-                       zapi_backup_nexthop_from_nexthop(api_nh, nh);
-
-                       i++;
-               }
-
-               api.backup_nexthop_num = i;
-       }
-
-       zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
-}
-
-void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance)
-{
-       struct zapi_route api;
-
-       memset(&api, 0, sizeof(api));
-       api.vrf_id = vrf_id;
-       api.type = ZEBRA_ROUTE_SHARP;
-       api.safi = SAFI_UNICAST;
-       api.instance = instance;
-       memcpy(&api.prefix, p, sizeof(*p));
-       zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
-
-       return;
-}
-
 void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import,
                               bool watch, bool connected)
 {
@@ -493,7 +600,8 @@ void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import,
                        command = ZEBRA_IMPORT_ROUTE_UNREGISTER;
        }
 
-       if (zclient_send_rnh(zclient, command, p, connected, vrf_id) < 0)
+       if (zclient_send_rnh(zclient, command, p, connected, vrf_id)
+           == ZCLIENT_SEND_FAILURE)
                zlog_warn("%s: Failure to send nexthop to zebra", __func__);
 }
 
@@ -679,7 +787,7 @@ void sharp_opaque_send(uint32_t type, uint32_t proto, uint32_t instance,
                        ret = zclient_send_opaque_unicast(zclient, type, proto,
                                                          instance, session_id,
                                                          buf, sizeof(buf));
-               if (ret < 0) {
+               if (ret == ZCLIENT_SEND_FAILURE) {
                        zlog_debug("%s: send_opaque() failed => %d",
                                   __func__, ret);
                        break;
@@ -768,7 +876,7 @@ void sharp_zebra_init(void)
        zclient->nexthop_update = sharp_nexthop_update;
        zclient->import_check_update = sharp_nexthop_update;
        zclient->nhg_notify_owner = nhg_notify_owner;
-
+       zclient->zebra_buffer_write_ready = sharp_zclient_buffer_ready;
        zclient->redistribute_route_add = sharp_redistribute_route;
        zclient->redistribute_route_del = sharp_redistribute_route;
        zclient->opaque_msg_handler = sharp_opaque_handler;
index 4a767ababf20833dd29596c2221f627617de2339..e7247f537340c3c60847dba79464623c5894a0d5 100644 (file)
@@ -32,10 +32,6 @@ extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label);
 extern void nhg_add(uint32_t id, const struct nexthop_group *nhg,
                    const struct nexthop_group *backup_nhg);
 extern void nhg_del(uint32_t id);
-extern void route_add(const struct prefix *p, vrf_id_t, uint8_t instance,
-                     uint32_t nhgid, const struct nexthop_group *nhg,
-                     const struct nexthop_group *backup_nhg);
-extern void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance);
 extern void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id,
                                      bool import, bool watch, bool connected);
 
@@ -43,7 +39,7 @@ extern void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
                                        uint8_t instance, uint32_t nhgid,
                                        const struct nexthop_group *nhg,
                                        const struct nexthop_group *backup_nhg,
-                                       uint32_t routes);
+                                       uint32_t routes, char *opaque);
 extern void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id,
                                       uint8_t instance, uint32_t routes);
 
index c0c31b5fd15f5313e89c6d121a9324d3e4c03514..1836f34979d3581863a3cc5420e622f7a620a224 100644 (file)
@@ -259,7 +259,7 @@ parts:
            - usr/lib/x86_64-linux-gnu/libssh.so*
         source: https://github.com/rtrlib/rtrlib.git
         source-type: git
-        source-tag: v0.6.3
+        source-tag: v0.7.0
         plugin: cmake
         configflags:
            - -DCMAKE_BUILD_TYPE=Release
@@ -392,6 +392,6 @@ parts:
 
 passthrough:
     layout:
-         /usr/lib/x86_64-linux-gnu/libyang:
-             bind: $SNAP/usr/lib/x86_64-linux-gnu/libyang
+         /usr/lib/x86_64-linux-gnu/libyang1:
+             bind: $SNAP/usr/lib/x86_64-linux-gnu/libyang1
 
index 51704426f0d1dd0c585dbc81bbc8a4733d99b4e0..a2a14751cf83e8d8c17ed3fcb561494073874d05 100644 (file)
@@ -46,12 +46,6 @@ const struct frr_yang_module_info frr_staticd_info = {
                                .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_tag_modify,
                        }
                },
-               {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/table-id",
-                       .cbs = {
-                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_table_id_modify,
-                       }
-               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop",
                        .cbs = {
@@ -72,7 +66,6 @@ const struct frr_yang_module_info frr_staticd_info = {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/onlink",
                        .cbs = {
                                .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_onlink_modify,
-                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_onlink_destroy,
                        }
                },
                {
@@ -131,12 +124,6 @@ const struct frr_yang_module_info frr_staticd_info = {
                                .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_tag_modify,
                        }
                },
-               {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/table-id",
-                       .cbs = {
-                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_table_id_modify,
-                       }
-               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop",
                        .cbs = {
@@ -157,7 +144,6 @@ const struct frr_yang_module_info frr_staticd_info = {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/onlink",
                        .cbs = {
                                .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_onlink_modify,
-                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_onlink_destroy,
                        }
                },
                {
index d145c31f77556977dccf62bfafe5740dd1f2e618..e85e1d0e9f509b55b72c54b63069193d9dceed74 100644 (file)
@@ -31,8 +31,6 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa
        struct nb_cb_destroy_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_tag_modify(
        struct nb_cb_modify_args *args);
-int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_table_id_modify(
-       struct nb_cb_modify_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_create(
        struct nb_cb_create_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_destroy(
@@ -43,8 +41,6 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa
        struct nb_cb_destroy_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_onlink_modify(
        struct nb_cb_modify_args *args);
-int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_onlink_destroy(
-       struct nb_cb_destroy_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_color_modify(
        struct nb_cb_modify_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_color_destroy(
@@ -75,8 +71,6 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr
        struct nb_cb_destroy_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_tag_modify(
        struct nb_cb_modify_args *args);
-int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_table_id_modify(
-       struct nb_cb_modify_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_create(
        struct nb_cb_create_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_destroy(
@@ -87,8 +81,6 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr
        struct nb_cb_destroy_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_onlink_modify(
        struct nb_cb_modify_args *args);
-int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_onlink_destroy(
-       struct nb_cb_destroy_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_color_modify(
        struct nb_cb_modify_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_color_destroy(
@@ -134,13 +126,11 @@ int routing_control_plane_protocols_name_validate(
        "/frr-routing:routing/control-plane-protocols/"                        \
        "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/"              \
        "frr-staticd:staticd/route-list[prefix='%s'][afi-safi='%s']/"          \
-       "path-list[distance='%u']"
+       "path-list[table-id='%u'][distance='%u']"
 
 
 #define FRR_STATIC_ROUTE_PATH_TAG_XPATH "/tag"
 
-#define FRR_STATIC_ROUTE_PATH_TABLEID_XPATH "/table-id"
-
 /* route-list/frr-nexthops */
 #define FRR_STATIC_ROUTE_NH_KEY_XPATH                                          \
        "/frr-nexthops/"                                                       \
@@ -161,7 +151,7 @@ int routing_control_plane_protocols_name_validate(
        "/frr-routing:routing/control-plane-protocols/"                        \
        "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/"              \
        "frr-staticd:staticd/route-list[prefix='%s'][afi-safi='%s']/"          \
-       "src-list[src-prefix='%s']/path-list[distance='%u']"
+       "src-list[src-prefix='%s']/path-list[table-id='%u'][distance='%u']"
 
 /* route-list/frr-nexthops */
 #define FRR_DEL_S_ROUTE_NH_KEY_XPATH                                           \
index 6e59f50a0020c8feb2d26eff94ffb66ff14d33b5..bf669957bf7cb2e5fa192feb5b8f6dcfbf6ba72c 100644 (file)
@@ -35,17 +35,40 @@ static int static_path_list_create(struct nb_cb_create_args *args)
 {
        struct route_node *rn;
        struct static_path *pn;
+       const struct lyd_node *vrf_dnode;
+       const char *vrf;
        uint8_t distance;
+       uint32_t table_id;
 
        switch (args->event) {
        case NB_EV_VALIDATE:
+               vrf_dnode = yang_dnode_get_parent(args->dnode,
+                                                 "control-plane-protocol");
+               vrf = yang_dnode_get_string(vrf_dnode, "./vrf");
+               table_id = yang_dnode_get_uint32(args->dnode, "./table-id");
+
+               /*
+                * TableId is not applicable for VRF. Consider the case of
+                * l3mdev, there is one uint32_t space to work with.
+                * A l3mdev device points at a specific table that it
+                * relates to and a set of interfaces it belongs to.
+                */
+               if (table_id && (strcmp(vrf, vrf_get_default_name()) != 0)
+                   && !vrf_is_backend_netns()) {
+                       snprintf(
+                               args->errmsg, args->errmsg_len,
+                               "%% table param only available when running on netns-based vrfs");
+                       return NB_ERR_VALIDATION;
+               }
+               break;
        case NB_EV_ABORT:
        case NB_EV_PREPARE:
                break;
        case NB_EV_APPLY:
                rn = nb_running_get_entry(args->dnode, NULL, true);
                distance = yang_dnode_get_uint8(args->dnode, "./distance");
-               pn = static_add_path(rn, distance);
+               table_id = yang_dnode_get_uint32(args->dnode, "./table-id");
+               pn = static_add_path(rn, table_id, distance);
                nb_running_set_entry(args->dnode, pn);
        }
 
@@ -80,44 +103,6 @@ static void static_path_list_tag_modify(struct nb_cb_modify_args *args,
        static_install_path(rn, pn, info->safi, info->svrf);
 }
 
-static int static_path_list_tableid_modify(struct nb_cb_modify_args *args,
-                                          const struct lyd_node *rn_dnode,
-                                          struct stable_info *info)
-{
-       struct static_path *pn;
-       struct route_node *rn;
-       uint32_t table_id;
-       const struct lyd_node *vrf_dnode;
-       const char *vrf;
-
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-               vrf_dnode = yang_dnode_get_parent(args->dnode,
-                                                 "control-plane-protocol");
-               vrf = yang_dnode_get_string(vrf_dnode, "./vrf");
-               table_id = yang_dnode_get_uint32(args->dnode, NULL);
-               if (table_id && (strcmp(vrf, vrf_get_default_name()) != 0)
-                   && !vrf_is_backend_netns()) {
-                       snprintf(args->errmsg, args->errmsg_len,
-                               "%% table param only available when running on netns-based vrfs");
-                       return NB_ERR_VALIDATION;
-               }
-               break;
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               break;
-       case NB_EV_APPLY:
-               table_id = yang_dnode_get_uint32(args->dnode, NULL);
-               pn = nb_running_get_entry(args->dnode, NULL, true);
-               pn->table_id = table_id;
-               rn = nb_running_get_entry(rn_dnode, NULL, true);
-               static_install_path(rn, pn, info->safi, info->svrf);
-               break;
-       }
-
-       return NB_OK;
-}
-
 static bool static_nexthop_create(struct nb_cb_create_args *args,
                                  const struct lyd_node *rn_dnode,
                                  struct stable_info *info)
@@ -302,9 +287,27 @@ static int static_nexthop_mpls_label_modify(struct nb_cb_modify_args *args)
 static int static_nexthop_onlink_modify(struct nb_cb_modify_args *args)
 {
        struct static_nexthop *nh;
+       static_types nh_type;
 
-       nh = nb_running_get_entry(args->dnode, NULL, true);
-       nh->onlink = yang_dnode_get_bool(args->dnode, NULL);
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               nh_type = yang_dnode_get_enum(args->dnode, "../nh-type");
+               if ((nh_type != STATIC_IPV4_GATEWAY_IFNAME)
+                   && (nh_type != STATIC_IPV6_GATEWAY_IFNAME)) {
+                       snprintf(
+                               args->errmsg, args->errmsg_len,
+                               "nexthop type is not the ipv4 or ipv6 interface type");
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               nh = nb_running_get_entry(args->dnode, NULL, true);
+               nh->onlink = yang_dnode_get_bool(args->dnode, NULL);
+               break;
+       }
 
        return NB_OK;
 }
@@ -332,9 +335,25 @@ static int static_nexthop_color_destroy(struct nb_cb_destroy_args *args)
 static int static_nexthop_bh_type_modify(struct nb_cb_modify_args *args)
 {
        struct static_nexthop *nh;
+       static_types nh_type;
 
-       nh = nb_running_get_entry(args->dnode, NULL, true);
-       nh->bh_type = yang_dnode_get_enum(args->dnode, NULL);
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               nh_type = yang_dnode_get_enum(args->dnode, "../nh-type");
+               if (nh_type != STATIC_BLACKHOLE) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                                "nexthop type is not the blackhole type");
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               nh = nb_running_get_entry(args->dnode, NULL, true);
+               nh->bh_type = yang_dnode_get_enum(args->dnode, NULL);
+               break;
+       }
 
        return NB_OK;
 }
@@ -578,38 +597,6 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/table-id
- */
-int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_table_id_modify(
-       struct nb_cb_modify_args *args)
-{
-       struct route_node *rn;
-       const struct lyd_node *rn_dnode;
-       struct stable_info *info;
-
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-               if (static_path_list_tableid_modify(args, NULL, NULL) != NB_OK)
-                       return NB_ERR_VALIDATION;
-               break;
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               break;
-       case NB_EV_APPLY:
-               rn_dnode = yang_dnode_get_parent(args->dnode, "route-list");
-               rn = nb_running_get_entry(rn_dnode, NULL, true);
-               info = route_table_get_info(rn->table);
-
-               if (static_path_list_tableid_modify(args, rn_dnode, info)
-                   != NB_OK)
-                       return NB_ERR_VALIDATION;
-               break;
-       }
-       return NB_OK;
-}
-
 /*
  * XPath:
  * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop
@@ -636,7 +623,7 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa
                info = route_table_get_info(rn->table);
 
                if (static_nexthop_create(args, rn_dnode, info) != NB_OK)
-                       return NB_ERR_VALIDATION;
+                       return NB_ERR_INCONSISTENCY;
                break;
        }
        return NB_OK;
@@ -673,17 +660,7 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_bh_type_modify(
        struct nb_cb_modify_args *args)
 {
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               break;
-       case NB_EV_APPLY:
-               if (static_nexthop_bh_type_modify(args) != NB_OK)
-                       return NB_ERR;
-               break;
-       }
-       return NB_OK;
+       return static_nexthop_bh_type_modify(args);
 }
 
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_bh_type_destroy(
@@ -709,33 +686,7 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_onlink_modify(
        struct nb_cb_modify_args *args)
 {
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               break;
-       case NB_EV_APPLY:
-               if (static_nexthop_onlink_modify(args) != NB_OK)
-                       return NB_ERR;
-
-               break;
-       }
-       return NB_OK;
-}
-int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_onlink_destroy(
-       struct nb_cb_destroy_args *args)
-{
-       /* onlink has a boolean type with default value,
-        * so no need to do any operations in destroy callback
-        */
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               break;
-       }
-       return NB_OK;
+       return static_nexthop_onlink_modify(args);
 }
 
 /*
@@ -1021,41 +972,6 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr
        return NB_OK;
 }
 
-/*
- * XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/table-id
- */
-int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_table_id_modify(
-       struct nb_cb_modify_args *args)
-{
-       struct route_node *rn;
-       const struct lyd_node *rn_dnode;
-       const struct lyd_node *src_dnode;
-       struct stable_info *info;
-
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-               if (static_path_list_tableid_modify(args, NULL, NULL) != NB_OK)
-                       return NB_ERR_VALIDATION;
-               break;
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               break;
-       case NB_EV_APPLY:
-               src_dnode = yang_dnode_get_parent(args->dnode, "src-list");
-               rn_dnode = yang_dnode_get_parent(src_dnode, "route-list");
-               rn = nb_running_get_entry(rn_dnode, NULL, true);
-               info = route_table_get_info(rn->table);
-
-               if (static_path_list_tableid_modify(args, src_dnode, info)
-                   != NB_OK)
-                       return NB_ERR_VALIDATION;
-
-               break;
-       }
-       return NB_OK;
-}
-
 /*
  * XPath:
  * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop
@@ -1124,17 +1040,7 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_bh_type_modify(
        struct nb_cb_modify_args *args)
 {
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               break;
-       case NB_EV_APPLY:
-               if (static_nexthop_bh_type_modify(args) != NB_OK)
-                       return NB_ERR;
-               break;
-       }
-       return NB_OK;
+       return static_nexthop_bh_type_modify(args);
 }
 
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_bh_type_destroy(
@@ -1161,35 +1067,7 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_onlink_modify(
        struct nb_cb_modify_args *args)
 {
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-               break;
-       case NB_EV_APPLY:
-               if (static_nexthop_onlink_modify(args) != NB_OK)
-                       return NB_ERR;
-
-               break;
-       }
-       return NB_OK;
-}
-
-
-int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_onlink_destroy(
-       struct nb_cb_destroy_args *args)
-{
-       /* onlink has a boolean type with default value,
-        * so no need to do any operations in destroy callback
-        */
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               break;
-       }
-       return NB_OK;
+       return static_nexthop_onlink_modify(args);
 }
 
 /*
index 05355c48fe800ba66617b5d9f05c1c31c758db70..1c436a66b079782beb0d333e2c2dc83838d5d268 100644 (file)
@@ -161,7 +161,8 @@ bool static_add_nexthop_validate(struct static_vrf *svrf, static_types type,
        return true;
 }
 
-struct static_path *static_add_path(struct route_node *rn, uint8_t distance)
+struct static_path *static_add_path(struct route_node *rn, uint32_t table_id,
+                                   uint8_t distance)
 {
        struct static_path *pn;
        struct static_route_info *si;
@@ -172,6 +173,7 @@ struct static_path *static_add_path(struct route_node *rn, uint8_t distance)
        pn = XCALLOC(MTYPE_STATIC_PATH, sizeof(struct static_path));
 
        pn->distance = distance;
+       pn->table_id = table_id;
        static_nexthop_list_init(&(pn->nexthop_list));
 
        si = rn->info;
index bd2cd78fd9338894cc1a5047d0e7286cfdb12015..470afb605d0a843ac6be5b8f5df5102a2ccd4fa4 100644 (file)
@@ -187,7 +187,7 @@ extern void static_del_route(struct route_node *rn, safi_t safi,
                             struct static_vrf *svrf);
 
 extern struct static_path *static_add_path(struct route_node *rn,
-                                          uint8_t distance);
+                                          uint32_t table_id, uint8_t distance);
 extern void static_del_path(struct route_node *rn, struct static_path *pn,
                            safi_t safi, struct static_vrf *svrf);
 
index c3c453f42d524cc516290658226196eb28153ffc..1488cc1775378452569c030f68450413c600e6c2 100644 (file)
@@ -68,7 +68,6 @@ static int static_route_leak(struct vty *vty, const char *svrf,
        char buf_src_prefix[PREFIX_STRLEN];
        char buf_nh_type[PREFIX_STRLEN];
        char buf_tag[PREFIX_STRLEN];
-       char buf_tableid[PREFIX_STRLEN];
        uint8_t label_stack_id = 0;
        const char *buf_gate_str;
        uint8_t distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
@@ -162,14 +161,14 @@ static int static_route_leak(struct vty *vty, const char *svrf,
                                 "frr-staticd:staticd", "staticd", svrf,
                                 buf_prefix,
                                 yang_afi_safi_value2identity(afi, safi),
-                                buf_src_prefix, distance);
+                                buf_src_prefix, table_id, distance);
                else
                        snprintf(xpath_prefix, sizeof(xpath_prefix),
                                 FRR_STATIC_ROUTE_INFO_KEY_XPATH,
                                 "frr-staticd:staticd", "staticd", svrf,
                                 buf_prefix,
                                 yang_afi_safi_value2identity(afi, safi),
-                                distance);
+                                table_id, distance);
 
                nb_cli_enqueue_change(vty, xpath_prefix, NB_OP_CREATE, NULL);
 
@@ -180,12 +179,6 @@ static int static_route_leak(struct vty *vty, const char *svrf,
                        sizeof(ab_xpath));
                nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY, buf_tag);
 
-               /* Table-Id processing */
-               snprintf(buf_tableid, sizeof(buf_tableid), "%u", table_id);
-               strlcpy(ab_xpath, xpath_prefix, sizeof(ab_xpath));
-               strlcat(ab_xpath, FRR_STATIC_ROUTE_PATH_TABLEID_XPATH,
-                       sizeof(ab_xpath));
-               nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY, buf_tableid);
                /* nexthop processing */
 
                snprintf(ab_xpath, sizeof(ab_xpath),
@@ -289,16 +282,16 @@ static int static_route_leak(struct vty *vty, const char *svrf,
                                 "frr-staticd:staticd", "staticd", svrf,
                                 buf_prefix,
                                 yang_afi_safi_value2identity(afi, safi),
-                                buf_src_prefix, distance, buf_nh_type, nh_svrf,
-                                buf_gate_str, ifname);
+                                buf_src_prefix, table_id, distance,
+                                buf_nh_type, nh_svrf, buf_gate_str, ifname);
                else
                        snprintf(ab_xpath, sizeof(ab_xpath),
                                 FRR_DEL_S_ROUTE_NH_KEY_XPATH,
                                 "frr-staticd:staticd", "staticd", svrf,
                                 buf_prefix,
                                 yang_afi_safi_value2identity(afi, safi),
-                                distance, buf_nh_type, nh_svrf, buf_gate_str,
-                                ifname);
+                                table_id, distance, buf_nh_type, nh_svrf,
+                                buf_gate_str, ifname);
 
                dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath);
                if (!dnode)
index 0bccbfbeadadcb84993ab95c27895b7a5c376677..19c578c60e2edcf37ad75a6d614643a0c298a367 100644 (file)
@@ -331,7 +331,8 @@ void static_zebra_nht_register(struct route_node *rn, struct static_nexthop *nh,
                static_nht_hash_free(nhtd);
        }
 
-       if (zclient_send_rnh(zclient, cmd, &p, false, nh->nh_vrf_id) < 0)
+       if (zclient_send_rnh(zclient, cmd, &p, false, nh->nh_vrf_id)
+           == ZCLIENT_SEND_FAILURE)
                zlog_warn("%s: Failure to send nexthop to zebra", __func__);
 }
 /*
index 5e809a81e6014063094746854592c3f5b3fb31e3..b1b8f92a87f1647c529c522aa0b8e7946d529861 100644 (file)
@@ -51,3 +51,4 @@
 /lib/test_zmq
 /ospf6d/test_lsdb
 /ospf6d/test_lsdb_clippy.c
+/zebra/test_lm_plugin
\ No newline at end of file
index 439891b559da5935b1199d9ab18d8e08e94ca1d0..936ffaaad58d4ec96605e4955d147e51a0a74767 100644 (file)
@@ -1265,7 +1265,8 @@ int main(void)
 {
        int i = 0;
        qobj_init();
-       bgp_master_init(thread_master_create(NULL), BGP_SOCKET_SNDBUF_SIZE);
+       bgp_master_init(thread_master_create(NULL), BGP_SOCKET_SNDBUF_SIZE,
+                       list_new());
        master = bm->master;
        bgp_option_set(BGP_OPT_NO_LISTEN);
        bgp_attr_init();
index 1b3f90434bd56735df74df7a550b91dce3b24d96..153b83897d988b3ed11a76656e43b356a1e8959c 100644 (file)
@@ -912,7 +912,7 @@ int main(void)
 
        qobj_init();
        master = thread_master_create(NULL);
-       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
+       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
        vrf_init(NULL, NULL, NULL, NULL, NULL);
        bgp_option_set(BGP_OPT_NO_LISTEN);
 
index 7fabaad7fa659a9c0f146c4ef3f5d3e2055b718a..f51076091357f83cd4083a658d6a14959ff0eab3 100644 (file)
@@ -1086,7 +1086,7 @@ int main(void)
        cmd_init(0);
        bgp_vty_init();
        master = thread_master_create("test mp attr");
-       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
+       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
        vrf_init(NULL, NULL, NULL, NULL, NULL);
        bgp_option_set(BGP_OPT_NO_LISTEN);
        bgp_attr_init();
index 520c460f159096d71e1e43c268827300b9549c38..92efd4c3d612b3a0e9d61ff7526cf005303eb0be 100644 (file)
@@ -393,7 +393,7 @@ static int global_test_init(void)
        qobj_init();
        master = thread_master_create(NULL);
        zclient = zclient_new(master, &zclient_options_default);
-       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
+       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
        vrf_init(NULL, NULL, NULL, NULL, NULL);
        bgp_option_set(BGP_OPT_NO_LISTEN);
 
index d2c093fbea2487eb600904825db89ddf4767180a..db5918745d6d8943aa40e5542c8e066492d0fc21 100644 (file)
@@ -59,7 +59,7 @@ int main(int argc, char *argv[])
        qobj_init();
        bgp_attr_init();
        master = thread_master_create(NULL);
-       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
+       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
        vrf_init(NULL, NULL, NULL, NULL, NULL);
        bgp_option_set(BGP_OPT_NO_LISTEN);
 
index 0a15886c108858faf35d8bf1328c363e2bc59a8b..123d97bc9700eeadd8a195e3be0468e5a106dd66 100644 (file)
@@ -1399,7 +1399,7 @@ static void bgp_startup(void)
        master = thread_master_create(NULL);
        yang_init(true);
        nb_init(master, bgpd_yang_modules, array_size(bgpd_yang_modules), false);
-       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
+       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
        bgp_option_set(BGP_OPT_NO_LISTEN);
        vrf_init(NULL, NULL, NULL, NULL, NULL);
        frr_pthread_init();
index 5fa604c7499c2be8ff90f8d6d23d1fffc32a2212..5b2028ffd409600a284f97bbf8f5e5060a808190 100644 (file)
@@ -69,6 +69,24 @@ test_find_adjacency(const struct isis_test_node *tnode, const char *hostname)
        return NULL;
 }
 
+mpls_label_t test_topology_node_ldp_label(const struct isis_topology *topology,
+                                         struct in_addr router_id)
+{
+       for (size_t i = 0; topology->nodes[i].hostname[0]; i++) {
+               const struct isis_test_node *tnode = &topology->nodes[i];
+               struct in_addr node_router_id;
+
+               if (!tnode->router_id)
+                       continue;
+
+               (void)inet_pton(AF_INET, tnode->router_id, &node_router_id);
+               if (IPV4_ADDR_SAME(&router_id, &node_router_id))
+                       return (50000 + (i + 1) * 100);
+       }
+
+       return MPLS_INVALID_LABEL;
+}
+
 static struct isis_lsp *lsp_add(struct lspdb_head *lspdb,
                                struct isis_area *area, int level,
                                const uint8_t *sysid, uint8_t pseudonode_id)
index 6fd0d3813e5ad4b26b2ce68ba854f3c3c9c3b166..3359a893acf3e9be6b019fad27c9913f535d74b1 100644 (file)
@@ -70,6 +70,9 @@ test_topology_find_node(const struct isis_topology *topology,
                        const char *hostname, uint8_t pseudonode_id);
 extern const struct isis_topology *
 test_topology_find(struct isis_topology *test_topologies, uint16_t number);
+extern mpls_label_t
+test_topology_node_ldp_label(const struct isis_topology *topology,
+                            struct in_addr router_id);
 extern int test_topology_load(const struct isis_topology *topology,
                              struct isis_area *area,
                              struct lspdb_head lspdb[]);
index 4c89a5be0a267663b79ef741a6fb5f513999e765..e06944a037e2ec267e5a358f277b25034acb9c64 100644 (file)
@@ -31,6 +31,7 @@
 #include "isisd/isisd.h"
 #include "isisd/isis_dynhn.h"
 #include "isisd/isis_misc.h"
+#include "isisd/isis_route.h"
 #include "isisd/isis_spf.h"
 #include "isisd/isis_spf_private.h"
 
@@ -39,6 +40,8 @@
 enum test_type {
        TEST_SPF = 1,
        TEST_REVERSE_SPF,
+       TEST_LFA,
+       TEST_RLFA,
        TEST_TI_LFA,
 };
 
@@ -72,6 +75,118 @@ static void test_run_spf(struct vty *vty, const struct isis_topology *topology,
        isis_spftree_del(spftree);
 }
 
+static void test_run_lfa(struct vty *vty, const struct isis_topology *topology,
+                        const struct isis_test_node *root,
+                        struct isis_area *area, struct lspdb_head *lspdb,
+                        int level, int tree,
+                        struct lfa_protected_resource *protected_resource)
+{
+       struct isis_spftree *spftree_self;
+       uint8_t flags;
+
+       /* Run forward SPF in the root node. */
+       flags = F_SPFTREE_NO_ADJACENCIES;
+       spftree_self = isis_spftree_new(area, lspdb, root->sysid, level, tree,
+                                       SPF_TYPE_FORWARD, flags);
+       isis_run_spf(spftree_self);
+
+       /* Run forward SPF on all adjacent routers. */
+       isis_spf_run_neighbors(spftree_self);
+
+       /* Compute the LFA repair paths. */
+       isis_lfa_compute(area, NULL, spftree_self, protected_resource);
+
+       /* Print the SPT and the corresponding main/backup routing tables. */
+       isis_print_spftree(vty, spftree_self);
+       vty_out(vty, "Main:\n");
+       isis_print_routes(vty, spftree_self, false, false);
+       vty_out(vty, "Backup:\n");
+       isis_print_routes(vty, spftree_self, false, true);
+
+       /* Cleanup everything. */
+       isis_spftree_del(spftree_self);
+}
+
+static void test_run_rlfa(struct vty *vty, const struct isis_topology *topology,
+                         const struct isis_test_node *root,
+                         struct isis_area *area, struct lspdb_head *lspdb,
+                         int level, int tree,
+                         struct lfa_protected_resource *protected_resource)
+{
+       struct isis_spftree *spftree_self;
+       struct isis_spftree *spftree_reverse;
+       struct isis_spftree *spftree_pc;
+       struct isis_spf_node *spf_node, *node;
+       struct rlfa *rlfa;
+       uint8_t flags;
+
+       /* Run forward SPF in the root node. */
+       flags = F_SPFTREE_NO_ADJACENCIES;
+       spftree_self = isis_spftree_new(area, lspdb, root->sysid, level, tree,
+                                       SPF_TYPE_FORWARD, flags);
+       isis_run_spf(spftree_self);
+
+       /* Run reverse SPF in the root node. */
+       spftree_reverse = isis_spf_reverse_run(spftree_self);
+
+       /* Run forward SPF on all adjacent routers. */
+       isis_spf_run_neighbors(spftree_self);
+
+       /* Compute the local LFA repair paths. */
+       isis_lfa_compute(area, NULL, spftree_self, protected_resource);
+
+       /* Compute the remote LFA repair paths. */
+       spftree_pc = isis_rlfa_compute(area, spftree_self, spftree_reverse, 0,
+                                      protected_resource);
+
+       /* Print the extended P-space and Q-space. */
+       vty_out(vty, "P-space (self):\n");
+       RB_FOREACH (node, isis_spf_nodes, &spftree_pc->lfa.p_space)
+               vty_out(vty, " %s\n", print_sys_hostname(node->sysid));
+       vty_out(vty, "\n");
+       RB_FOREACH (spf_node, isis_spf_nodes, &spftree_self->adj_nodes) {
+               if (RB_EMPTY(isis_spf_nodes, &spf_node->lfa.p_space))
+                       continue;
+               vty_out(vty, "P-space (%s):\n",
+                       print_sys_hostname(spf_node->sysid));
+               RB_FOREACH (node, isis_spf_nodes, &spf_node->lfa.p_space)
+                       vty_out(vty, " %s\n", print_sys_hostname(node->sysid));
+               vty_out(vty, "\n");
+       }
+       vty_out(vty, "Q-space:\n");
+       RB_FOREACH (node, isis_spf_nodes, &spftree_pc->lfa.q_space)
+               vty_out(vty, " %s\n", print_sys_hostname(node->sysid));
+       vty_out(vty, "\n");
+
+       /* Print the post-convergence SPT. */
+       isis_print_spftree(vty, spftree_pc);
+
+       /*
+        * Activate the computed RLFAs (if any) using artificial LDP labels for
+        * the PQ nodes.
+        */
+       frr_each_safe (rlfa_tree, &spftree_self->lfa.remote.rlfas, rlfa) {
+               struct zapi_rlfa_response response = {};
+
+               response.pq_label = test_topology_node_ldp_label(
+                       topology, rlfa->pq_address);
+               assert(response.pq_label != MPLS_INVALID_LABEL);
+               isis_rlfa_activate(spftree_self, rlfa, &response);
+       }
+
+       /* Print the SPT and the corresponding main/backup routing tables. */
+       isis_print_spftree(vty, spftree_self);
+       vty_out(vty, "Main:\n");
+       isis_print_routes(vty, spftree_self, false, false);
+       vty_out(vty, "Backup:\n");
+       isis_print_routes(vty, spftree_self, false, true);
+
+       /* Cleanup everything. */
+       isis_spftree_del(spftree_self);
+       isis_spftree_del(spftree_reverse);
+       isis_spftree_del(spftree_pc);
+}
+
 static void test_run_ti_lfa(struct vty *vty,
                            const struct isis_topology *topology,
                            const struct isis_test_node *root,
@@ -120,7 +235,9 @@ static void test_run_ti_lfa(struct vty *vty,
                vty_out(vty, " %s\n", print_sys_hostname(node->sysid));
        vty_out(vty, "\n");
 
-       /* Print the post-convergence SPT and the correspoding routing table. */
+       /*
+        * Print the post-convergence SPT and the corresponding routing table.
+        */
        isis_print_spftree(vty, spftree_pc);
        isis_print_routes(vty, spftree_self, false, true);
 
@@ -202,6 +319,16 @@ static int test_run(struct vty *vty, const struct isis_topology *topology,
                                             &area->lspdb[level - 1], level,
                                             tree, true);
                                break;
+                       case TEST_LFA:
+                               test_run_lfa(vty, topology, root, area,
+                                            &area->lspdb[level - 1], level,
+                                            tree, &protected_resource);
+                               break;
+                       case TEST_RLFA:
+                               test_run_rlfa(vty, topology, root, area,
+                                             &area->lspdb[level - 1], level,
+                                             tree, &protected_resource);
+                               break;
                        case TEST_TI_LFA:
                                test_run_ti_lfa(vty, topology, root, area,
                                                &area->lspdb[level - 1], level,
@@ -221,10 +348,12 @@ static int test_run(struct vty *vty, const struct isis_topology *topology,
 }
 
 DEFUN(test_isis, test_isis_cmd,
-      "test isis topology (1-13) root HOSTNAME\
+      "test isis topology (1-14) root HOSTNAME\
          <\
           spf\
           |reverse-spf\
+          |lfa system-id WORD [pseudonode-id <1-255>]\
+          |remote-lfa system-id WORD [pseudonode-id <1-255>]\
           |ti-lfa system-id WORD [pseudonode-id <1-255>] [node-protection]\
         >\
         [display-lspdb] [<ipv4-only|ipv6-only>] [<level-1-only|level-2-only>]",
@@ -236,6 +365,16 @@ DEFUN(test_isis, test_isis_cmd,
       "SPF root hostname\n"
       "Normal Shortest Path First\n"
       "Reverse Shortest Path First\n"
+      "Classic LFA\n"
+      "System ID\n"
+      "System ID\n"
+      "Pseudonode-ID\n"
+      "Pseudonode-ID\n"
+      "Remote LFA\n"
+      "System ID\n"
+      "System ID\n"
+      "Pseudonode-ID\n"
+      "Pseudonode-ID\n"
       "Topology Independent LFA\n"
       "System ID\n"
       "System ID\n"
@@ -281,7 +420,23 @@ DEFUN(test_isis, test_isis_cmd,
                test_type = TEST_SPF;
        else if (argv_find(argv, argc, "reverse-spf", &idx))
                test_type = TEST_REVERSE_SPF;
-       else if (argv_find(argv, argc, "ti-lfa", &idx)) {
+       else if (argv_find(argv, argc, "lfa", &idx)) {
+               test_type = TEST_LFA;
+
+               fail_sysid_str = argv[idx + 2]->arg;
+               if (argv_find(argv, argc, "pseudonode-id", &idx))
+                       fail_pseudonode_id =
+                               strtoul(argv[idx + 1]->arg, NULL, 10);
+               protection_type = LFA_LINK_PROTECTION;
+       } else if (argv_find(argv, argc, "remote-lfa", &idx)) {
+               test_type = TEST_RLFA;
+
+               fail_sysid_str = argv[idx + 2]->arg;
+               if (argv_find(argv, argc, "pseudonode-id", &idx))
+                       fail_pseudonode_id =
+                               strtoul(argv[idx + 1]->arg, NULL, 10);
+               protection_type = LFA_LINK_PROTECTION;
+       } else if (argv_find(argv, argc, "ti-lfa", &idx)) {
                test_type = TEST_TI_LFA;
 
                fail_sysid_str = argv[idx + 2]->arg;
@@ -404,7 +559,7 @@ int main(int argc, char **argv)
        listnode_add(im->isis, isis);
        SET_FLAG(im->options, F_ISIS_UNIT_TEST);
        debug_spf_events |= DEBUG_SPF_EVENTS;
-       debug_tilfa |= DEBUG_TILFA;
+       debug_lfa |= DEBUG_LFA;
        debug_events |= DEBUG_EVENTS;
        debug_rte_events |= DEBUG_RTE_EVENTS;
 
index 6bc5442f1e927003d8d7084cffb3f9f969e9e75a..f8f65ffdf795eaf8ebe83298de7105f6c3648a3b 100644 (file)
@@ -15,6 +15,34 @@ test isis topology 13 root rt1 spf ipv4-only
 test isis topology 4 root rt1 reverse-spf ipv4-only
 test isis topology 11 root rt1 reverse-spf
 
+test isis topology 1 root rt1 lfa system-id rt2
+test isis topology 2 root rt4 lfa system-id rt1 pseudonode-id 1
+test isis topology 2 root rt4 lfa system-id rt6
+test isis topology 3 root rt1 lfa system-id rt2
+test isis topology 3 root rt1 lfa system-id rt3
+test isis topology 7 root rt1 lfa system-id rt4
+test isis topology 7 root rt7 lfa system-id rt8
+test isis topology 7 root rt8 lfa system-id rt11
+test isis topology 9 root rt3 lfa system-id rt1
+test isis topology 10 root rt8 lfa system-id rt5
+test isis topology 11 root rt3 lfa system-id rt5
+test isis topology 13 root rt4 lfa system-id rt3
+test isis topology 14 root rt1 lfa system-id rt1 pseudonode-id 1
+test isis topology 14 root rt1 lfa system-id rt2
+test isis topology 14 root rt5 lfa system-id rt4
+
+test isis topology 1 root rt1 remote-lfa system-id rt2
+test isis topology 2 root rt5 remote-lfa system-id rt1 pseudonode-id 1
+test isis topology 3 root rt5 remote-lfa system-id rt4 ipv4-only
+test isis topology 3 root rt5 remote-lfa system-id rt3 ipv4-only
+test isis topology 5 root rt1 remote-lfa system-id rt2 ipv4-only
+test isis topology 6 root rt4 remote-lfa system-id rt3 ipv4-only
+test isis topology 7 root rt11 remote-lfa system-id rt8 ipv4-only
+test isis topology 7 root rt6 remote-lfa system-id rt5 ipv4-only
+test isis topology 8 root rt2 remote-lfa system-id rt5 ipv4-only
+test isis topology 11 root rt2 remote-lfa system-id rt4
+test isis topology 13 root rt1 remote-lfa system-id rt3 ipv4-only
+
 test isis topology 1 root rt1 ti-lfa system-id rt2
 test isis topology 2 root rt1 ti-lfa system-id rt3
 test isis topology 2 root rt1 ti-lfa system-id rt1 pseudonode-id 1
index d24176a097e08f3c98b04eda169dcc1dc8266fd9..024f7256e0bd61df7daa32337d5625a08d7b629e 100644 (file)
@@ -720,6 +720,2313 @@ IS-IS L1 IPv6 routing table:
  2001:db8::5/128  30      -          rt3      16051          \r
  2001:db8::6/128  40      -          rt3      16061          \r
 \r
+test# \r
+test# test isis topology 1 root rt1 lfa system-id rt2\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt2                  -         rt4(4)\r
+                                         rt3                  -         rt5(4)\r
+10.0.255.4/32        IP TE        30     rt2                  -         rt4(4)\r
+10.0.255.5/32        IP TE        30     rt3                  -         rt5(4)\r
+10.0.255.6/32        IP TE        40     rt2                  -         rt6(4)\r
+                                         rt3                  -         \r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  40      -          rt2      16060          \r
+                        -          rt3      16060          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+2001:db8::1/128      IP6 internal 0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+2001:db8::2/128      IP6 internal 20     rt2                  -         rt2(4)\r
+2001:db8::3/128      IP6 internal 20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt2                  -         rt4(4)\r
+                                         rt3                  -         rt5(4)\r
+2001:db8::4/128      IP6 internal 30     rt2                  -         rt4(4)\r
+2001:db8::5/128      IP6 internal 30     rt3                  -         rt5(4)\r
+2001:db8::6/128      IP6 internal 40     rt2                  -         rt6(4)\r
+                                         rt3                  -         \r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  0       -          -        -              \r
+ 2001:db8::2/128  20      -          rt2      implicit-null  \r
+ 2001:db8::3/128  20      -          rt3      implicit-null  \r
+ 2001:db8::4/128  30      -          rt2      16041          \r
+ 2001:db8::5/128  30      -          rt3      16051          \r
+ 2001:db8::6/128  40      -          rt2      16061          \r
+                          -          rt3      16061          \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+test# test isis topology 2 root rt4 lfa system-id rt1 pseudonode-id 1\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt4                                                                   \r
+10.0.255.4/32        IP internal  0                                     rt4(4)\r
+rt1                  TE-IS        10     rt1                  -         rt4(4)\r
+rt5                  TE-IS        10     rt5                  -         rt4(4)\r
+rt6                  TE-IS        10     rt6                  -         rt4(4)\r
+rt1                  pseudo_TE-IS 20     rt1                  -         rt1(4)\r
+                                         rt5                  -         rt5(4)\r
+10.0.255.1/32        IP TE        20     rt1                  -         rt1(4)\r
+10.0.255.5/32        IP TE        20     rt5                  -         rt5(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt2                  TE-IS        25     rt1                  -         rt1(4)\r
+10.0.255.2/32        IP TE        35     rt1                  -         rt2(4)\r
+rt3                  TE-IS        40     rt1                  -         rt1(4)\r
+10.0.255.3/32        IP TE        50     rt1                  -         rt3(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  20      -          rt1      implicit-null  \r
+ 10.0.255.2/32  35      -          rt1      16020          \r
+ 10.0.255.3/32  50      -          rt1      16030          \r
+ 10.0.255.4/32  0       -          -        -              \r
+ 10.0.255.5/32  20      -          rt5      implicit-null  \r
+ 10.0.255.6/32  20      -          rt6      implicit-null  \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.2/32  40      -          rt2      implicit-null  \r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt4                                                                   \r
+2001:db8::4/128      IP6 internal 0                                     rt4(4)\r
+rt1                  TE-IS        10     rt1                  -         rt4(4)\r
+rt5                  TE-IS        10     rt5                  -         rt4(4)\r
+rt6                  TE-IS        10     rt6                  -         rt4(4)\r
+rt1                  pseudo_TE-IS 20     rt1                  -         rt1(4)\r
+                                         rt5                  -         rt5(4)\r
+2001:db8::1/128      IP6 internal 20     rt1                  -         rt1(4)\r
+2001:db8::5/128      IP6 internal 20     rt5                  -         rt5(4)\r
+2001:db8::6/128      IP6 internal 20     rt6                  -         rt6(4)\r
+rt2                  TE-IS        25     rt1                  -         rt1(4)\r
+2001:db8::2/128      IP6 internal 35     rt1                  -         rt2(4)\r
+rt3                  TE-IS        40     rt1                  -         rt1(4)\r
+2001:db8::3/128      IP6 internal 50     rt1                  -         rt3(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  20      -          rt1      implicit-null  \r
+ 2001:db8::2/128  35      -          rt1      16021          \r
+ 2001:db8::3/128  50      -          rt1      16031          \r
+ 2001:db8::4/128  0       -          -        -              \r
+ 2001:db8::5/128  20      -          rt5      implicit-null  \r
+ 2001:db8::6/128  20      -          rt6      implicit-null  \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::2/128  40      -          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
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt4                                                                   \r
+10.0.255.4/32        IP internal  0                                     rt4(4)\r
+rt1                  TE-IS        10     rt1                  -         rt4(4)\r
+rt5                  TE-IS        10     rt5                  -         rt4(4)\r
+rt6                  TE-IS        10     rt6                  -         rt4(4)\r
+rt1                  pseudo_TE-IS 20     rt1                  -         rt1(4)\r
+                                         rt5                  -         rt5(4)\r
+10.0.255.1/32        IP TE        20     rt1                  -         rt1(4)\r
+10.0.255.5/32        IP TE        20     rt5                  -         rt5(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt2                  TE-IS        25     rt1                  -         rt1(4)\r
+10.0.255.2/32        IP TE        35     rt1                  -         rt2(4)\r
+rt3                  TE-IS        40     rt1                  -         rt1(4)\r
+10.0.255.3/32        IP TE        50     rt1                  -         rt3(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  20      -          rt1      implicit-null  \r
+ 10.0.255.2/32  35      -          rt1      16020          \r
+ 10.0.255.3/32  50      -          rt1      16030          \r
+ 10.0.255.4/32  0       -          -        -              \r
+ 10.0.255.5/32  20      -          rt5      implicit-null  \r
+ 10.0.255.6/32  20      -          rt6      implicit-null  \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)  \r
+ -----------------------------------------------------\r
+ 10.0.255.6/32  20      -          rt5      16060     \r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt4                                                                   \r
+2001:db8::4/128      IP6 internal 0                                     rt4(4)\r
+rt1                  TE-IS        10     rt1                  -         rt4(4)\r
+rt5                  TE-IS        10     rt5                  -         rt4(4)\r
+rt6                  TE-IS        10     rt6                  -         rt4(4)\r
+rt1                  pseudo_TE-IS 20     rt1                  -         rt1(4)\r
+                                         rt5                  -         rt5(4)\r
+2001:db8::1/128      IP6 internal 20     rt1                  -         rt1(4)\r
+2001:db8::5/128      IP6 internal 20     rt5                  -         rt5(4)\r
+2001:db8::6/128      IP6 internal 20     rt6                  -         rt6(4)\r
+rt2                  TE-IS        25     rt1                  -         rt1(4)\r
+2001:db8::2/128      IP6 internal 35     rt1                  -         rt2(4)\r
+rt3                  TE-IS        40     rt1                  -         rt1(4)\r
+2001:db8::3/128      IP6 internal 50     rt1                  -         rt3(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  20      -          rt1      implicit-null  \r
+ 2001:db8::2/128  35      -          rt1      16021          \r
+ 2001:db8::3/128  50      -          rt1      16031          \r
+ 2001:db8::4/128  0       -          -        -              \r
+ 2001:db8::5/128  20      -          rt5      implicit-null  \r
+ 2001:db8::6/128  20      -          rt6      implicit-null  \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)  \r
+ -------------------------------------------------------\r
+ 2001:db8::6/128  20      -          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
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt5                  TE-IS        30     rt2                  -         rt4(4)\r
+rt6                  TE-IS        30     rt2                  -         rt4(4)\r
+10.0.255.4/32        IP TE        30     rt2                  -         rt4(4)\r
+10.0.255.5/32        IP TE        40     rt2                  -         rt5(4)\r
+10.0.255.6/32        IP TE        40     rt2                  -         rt6(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+ 10.0.255.5/32  40      -          rt2      16050          \r
+ 10.0.255.6/32  40      -          rt2      16060          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)  \r
+ -----------------------------------------------------\r
+ 10.0.255.2/32  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
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+test# test isis topology 3 root rt1 lfa system-id rt3\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt5                  TE-IS        30     rt2                  -         rt4(4)\r
+rt6                  TE-IS        30     rt2                  -         rt4(4)\r
+10.0.255.4/32        IP TE        30     rt2                  -         rt4(4)\r
+10.0.255.5/32        IP TE        40     rt2                  -         rt5(4)\r
+10.0.255.6/32        IP TE        40     rt2                  -         rt6(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+ 10.0.255.5/32  40      -          rt2      16050          \r
+ 10.0.255.6/32  40      -          rt2      16060          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)  \r
+ -----------------------------------------------------\r
+ 10.0.255.3/32  20      -          rt2      16030     \r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+test# test isis topology 7 root rt1 lfa system-id rt4\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt4                  TE-IS        10     rt4                  -         rt1(4)\r
+rt5                  TE-IS        20     rt4                  -         rt4(4)\r
+rt7                  TE-IS        20     rt4                  -         rt4(4)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+rt2                  TE-IS        30     rt4                  -         rt5(4)\r
+rt6                  TE-IS        30     rt4                  -         rt5(4)\r
+rt8                  TE-IS        30     rt4                  -         rt5(4)\r
+                                                                        rt7(4)\r
+10.0.255.5/32        IP TE        30     rt4                  -         rt5(4)\r
+10.0.255.7/32        IP TE        30     rt4                  -         rt7(4)\r
+rt10                 TE-IS        40     rt4                  -         rt7(4)\r
+rt3                  TE-IS        40     rt4                  -         rt2(4)\r
+                                                                        rt6(4)\r
+rt9                  TE-IS        40     rt4                  -         rt8(4)\r
+rt11                 TE-IS        40     rt4                  -         rt8(4)\r
+10.0.255.2/32        IP TE        40     rt4                  -         rt2(4)\r
+10.0.255.6/32        IP TE        40     rt4                  -         rt6(4)\r
+10.0.255.8/32        IP TE        40     rt4                  -         rt8(4)\r
+rt12                 TE-IS        50     rt4                  -         rt9(4)\r
+                                                                        rt11(4)\r
+10.0.255.10/32       IP TE        50     rt4                  -         rt10(4)\r
+10.0.255.3/32        IP TE        50     rt4                  -         rt3(4)\r
+10.0.255.9/32        IP TE        50     rt4                  -         rt9(4)\r
+10.0.255.11/32       IP TE        50     rt4                  -         rt11(4)\r
+10.0.255.12/32       IP TE        60     rt4                  -         rt12(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)       \r
+ -----------------------------------------------------------\r
+ 10.0.255.1/32   0       -          -        -              \r
+ 10.0.255.2/32   40      -          rt4      16020          \r
+ 10.0.255.3/32   50      -          rt4      16030          \r
+ 10.0.255.4/32   20      -          rt4      implicit-null  \r
+ 10.0.255.5/32   30      -          rt4      16050          \r
+ 10.0.255.6/32   40      -          rt4      16060          \r
+ 10.0.255.7/32   30      -          rt4      16070          \r
+ 10.0.255.8/32   40      -          rt4      16080          \r
+ 10.0.255.9/32   50      -          rt4      16090          \r
+ 10.0.255.10/32  50      -          rt4      16100          \r
+ 10.0.255.11/32  50      -          rt4      16110          \r
+ 10.0.255.12/32  60      -          rt4      16120          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)       \r
+ -----------------------------------------------------------\r
+ 10.0.255.2/32   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
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+rt4                  TE-IS        10     rt4                  -         rt1(4)\r
+rt2                  TE-IS        40     rt2                  -         rt1(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+test# test isis topology 7 root rt7 lfa system-id rt8\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt7                                                                   \r
+10.0.255.7/32        IP internal  0                                     rt7(4)\r
+rt4                  TE-IS        10     rt4                  -         rt7(4)\r
+rt8                  TE-IS        10     rt8                  -         rt7(4)\r
+rt10                 TE-IS        20     rt10                 -         rt7(4)\r
+rt1                  TE-IS        20     rt4                  -         rt4(4)\r
+rt5                  TE-IS        20     rt4                  -         rt4(4)\r
+                                         rt8                  -         rt8(4)\r
+rt9                  TE-IS        20     rt8                  -         rt8(4)\r
+rt11                 TE-IS        20     rt8                  -         rt8(4)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+10.0.255.8/32        IP TE        20     rt8                  -         rt8(4)\r
+rt2                  TE-IS        30     rt4                  -         rt5(4)\r
+                                         rt8                  -         \r
+rt6                  TE-IS        30     rt4                  -         rt5(4)\r
+                                         rt8                  -         \r
+rt12                 TE-IS        30     rt8                  -         rt9(4)\r
+                                                                        rt11(4)\r
+10.0.255.10/32       IP TE        30     rt10                 -         rt10(4)\r
+10.0.255.1/32        IP TE        30     rt4                  -         rt1(4)\r
+10.0.255.5/32        IP TE        30     rt4                  -         rt5(4)\r
+                                         rt8                  -         \r
+10.0.255.9/32        IP TE        30     rt8                  -         rt9(4)\r
+10.0.255.11/32       IP TE        30     rt8                  -         rt11(4)\r
+rt3                  TE-IS        40     rt4                  -         rt2(4)\r
+                                         rt8                  -         rt6(4)\r
+10.0.255.2/32        IP TE        40     rt4                  -         rt2(4)\r
+                                         rt8                  -         \r
+10.0.255.6/32        IP TE        40     rt4                  -         rt6(4)\r
+                                         rt8                  -         \r
+10.0.255.12/32       IP TE        40     rt8                  -         rt12(4)\r
+10.0.255.3/32        IP TE        50     rt4                  -         rt3(4)\r
+                                         rt8                  -         \r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)       \r
+ -----------------------------------------------------------\r
+ 10.0.255.1/32   30      -          rt4      16010          \r
+ 10.0.255.2/32   40      -          rt4      16020          \r
+                         -          rt8      16020          \r
+ 10.0.255.3/32   50      -          rt4      16030          \r
+                         -          rt8      16030          \r
+ 10.0.255.4/32   20      -          rt4      implicit-null  \r
+ 10.0.255.5/32   30      -          rt4      16050          \r
+                         -          rt8      16050          \r
+ 10.0.255.6/32   40      -          rt4      16060          \r
+                         -          rt8      16060          \r
+ 10.0.255.7/32   0       -          -        -              \r
+ 10.0.255.8/32   20      -          rt8      implicit-null  \r
+ 10.0.255.9/32   30      -          rt8      16090          \r
+ 10.0.255.10/32  30      -          rt10     implicit-null  \r
+ 10.0.255.11/32  30      -          rt8      16110          \r
+ 10.0.255.12/32  40      -          rt8      16120          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\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
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt7                                                                   \r
+rt4                  TE-IS        10     rt4                  -         rt7(4)\r
+rt8                  TE-IS        10     rt8                  -         rt7(4)\r
+rt10                 TE-IS        20     rt10                 -         rt7(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+test# test isis topology 7 root rt8 lfa system-id rt11\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt8                                                                   \r
+10.0.255.8/32        IP internal  0                                     rt8(4)\r
+rt5                  TE-IS        10     rt5                  -         rt8(4)\r
+rt7                  TE-IS        10     rt7                  -         rt8(4)\r
+rt9                  TE-IS        10     rt9                  -         rt8(4)\r
+rt11                 TE-IS        10     rt11                 -         rt8(4)\r
+rt2                  TE-IS        20     rt5                  -         rt5(4)\r
+rt4                  TE-IS        20     rt5                  -         rt5(4)\r
+                                         rt7                  -         rt7(4)\r
+rt6                  TE-IS        20     rt5                  -         rt5(4)\r
+rt12                 TE-IS        20     rt9                  -         rt9(4)\r
+                                         rt11                 -         rt11(4)\r
+rt10                 TE-IS        20     rt11                 -         rt11(4)\r
+10.0.255.5/32        IP TE        20     rt5                  -         rt5(4)\r
+10.0.255.7/32        IP TE        20     rt7                  -         rt7(4)\r
+10.0.255.9/32        IP TE        20     rt9                  -         rt9(4)\r
+10.0.255.11/32       IP TE        20     rt11                 -         rt11(4)\r
+rt3                  TE-IS        30     rt5                  -         rt2(4)\r
+                                                                        rt6(4)\r
+rt1                  TE-IS        30     rt5                  -         rt4(4)\r
+                                         rt7                  -         \r
+10.0.255.2/32        IP TE        30     rt5                  -         rt2(4)\r
+10.0.255.4/32        IP TE        30     rt5                  -         rt4(4)\r
+                                         rt7                  -         \r
+10.0.255.6/32        IP TE        30     rt5                  -         rt6(4)\r
+10.0.255.12/32       IP TE        30     rt9                  -         rt12(4)\r
+                                         rt11                 -         \r
+10.0.255.10/32       IP TE        30     rt11                 -         rt10(4)\r
+10.0.255.3/32        IP TE        40     rt5                  -         rt3(4)\r
+10.0.255.1/32        IP TE        40     rt5                  -         rt1(4)\r
+                                         rt7                  -         \r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)       \r
+ -----------------------------------------------------------\r
+ 10.0.255.1/32   40      -          rt5      16010          \r
+                         -          rt7      16010          \r
+ 10.0.255.2/32   30      -          rt5      16020          \r
+ 10.0.255.3/32   40      -          rt5      16030          \r
+ 10.0.255.4/32   30      -          rt5      16040          \r
+                         -          rt7      16040          \r
+ 10.0.255.5/32   20      -          rt5      implicit-null  \r
+ 10.0.255.6/32   30      -          rt5      16060          \r
+ 10.0.255.7/32   20      -          rt7      implicit-null  \r
+ 10.0.255.8/32   0       -          -        -              \r
+ 10.0.255.9/32   20      -          rt9      implicit-null  \r
+ 10.0.255.10/32  30      -          rt11     16100          \r
+ 10.0.255.11/32  20      -          rt11     implicit-null  \r
+ 10.0.255.12/32  30      -          rt9      16120          \r
+                         -          rt11     16120          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)  \r
+ ------------------------------------------------------\r
+ 10.0.255.10/32  30      -          rt7      16100     \r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt8                                                                   \r
+rt5                  TE-IS        10     rt5                  -         rt8(4)\r
+rt7                  TE-IS        10     rt7                  -         rt8(4)\r
+rt9                  TE-IS        10     rt9                  -         rt8(4)\r
+rt11                 TE-IS        10     rt11                 -         rt8(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+test# test isis topology 9 root rt3 lfa system-id rt1\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt3                                                                   \r
+10.0.255.3/32        IP internal  0                                     rt3(4)\r
+rt1                  TE-IS        10     rt1                  -         rt3(4)\r
+rt2                  TE-IS        20     rt1                  -         rt1(4)\r
+10.0.255.1/32        IP TE        20     rt1                  -         rt1(4)\r
+rt4                  TE-IS        30     rt1                  -         rt2(4)\r
+10.0.255.2/32        IP TE        30     rt1                  -         rt2(4)\r
+rt5                  TE-IS        40     rt1                  -         rt4(4)\r
+10.0.255.4/32        IP TE        40     rt1                  -         rt4(4)\r
+rt9                  TE-IS        50     rt1                  -         rt5(4)\r
+10.0.255.5/32        IP TE        50     rt1                  -         rt5(4)\r
+rt6                  TE-IS        60     rt1                  -         rt4(4)\r
+                                                                        rt9(4)\r
+rt7                  TE-IS        60     rt1                  -         rt4(4)\r
+                                                                        rt9(4)\r
+rt8                  TE-IS        60     rt1                  -         rt4(4)\r
+                                                                        rt9(4)\r
+10.0.255.9/32        IP TE        60     rt1                  -         rt9(4)\r
+10.0.255.6/32        IP TE        70     rt1                  -         rt6(4)\r
+10.0.255.7/32        IP TE        70     rt1                  -         rt7(4)\r
+10.0.255.8/32        IP TE        70     rt1                  -         rt8(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  20      -          rt1      implicit-null  \r
+ 10.0.255.2/32  30      -          rt1      16020          \r
+ 10.0.255.3/32  0       -          -        -              \r
+ 10.0.255.4/32  40      -          rt1      16040          \r
+ 10.0.255.5/32  50      -          rt1      16050          \r
+ 10.0.255.6/32  70      -          rt1      16060          \r
+ 10.0.255.7/32  70      -          rt1      16070          \r
+ 10.0.255.8/32  70      -          rt1      16080          \r
+ 10.0.255.9/32  60      -          rt1      16090          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  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
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt3                                                                   \r
+2001:db8::3/128      IP6 internal 0                                     rt3(4)\r
+rt1                  TE-IS        10     rt1                  -         rt3(4)\r
+rt2                  TE-IS        20     rt1                  -         rt1(4)\r
+2001:db8::1/128      IP6 internal 20     rt1                  -         rt1(4)\r
+rt4                  TE-IS        30     rt1                  -         rt2(4)\r
+2001:db8::2/128      IP6 internal 30     rt1                  -         rt2(4)\r
+rt5                  TE-IS        40     rt1                  -         rt4(4)\r
+2001:db8::4/128      IP6 internal 40     rt1                  -         rt4(4)\r
+rt9                  TE-IS        50     rt1                  -         rt5(4)\r
+2001:db8::5/128      IP6 internal 50     rt1                  -         rt5(4)\r
+rt6                  TE-IS        60     rt1                  -         rt4(4)\r
+                                                                        rt9(4)\r
+rt7                  TE-IS        60     rt1                  -         rt4(4)\r
+                                                                        rt9(4)\r
+rt8                  TE-IS        60     rt1                  -         rt4(4)\r
+                                                                        rt9(4)\r
+2001:db8::9/128      IP6 internal 60     rt1                  -         rt9(4)\r
+2001:db8::6/128      IP6 internal 70     rt1                  -         rt6(4)\r
+2001:db8::7/128      IP6 internal 70     rt1                  -         rt7(4)\r
+2001:db8::8/128      IP6 internal 70     rt1                  -         rt8(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  20      -          rt1      implicit-null  \r
+ 2001:db8::2/128  30      -          rt1      16021          \r
+ 2001:db8::3/128  0       -          -        -              \r
+ 2001:db8::4/128  40      -          rt1      16041          \r
+ 2001:db8::5/128  50      -          rt1      16051          \r
+ 2001:db8::6/128  70      -          rt1      16061          \r
+ 2001:db8::7/128  70      -          rt1      16071          \r
+ 2001:db8::8/128  70      -          rt1      16081          \r
+ 2001:db8::9/128  60      -          rt1      16091          \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\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
+\r
+test# test isis topology 10 root rt8 lfa system-id rt5\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt8                                                                   \r
+10.0.255.8/32        IP internal  0                                     rt8(4)\r
+rt5                  TE-IS        10     rt5                  -         rt8(4)\r
+rt2                  TE-IS        20     rt5                  -         rt5(4)\r
+10.0.255.5/32        IP TE        20     rt5                  -         rt5(4)\r
+rt1                  TE-IS        30     rt5                  -         rt2(4)\r
+10.0.255.2/32        IP TE        30     rt5                  -         rt2(4)\r
+10.0.255.1/32        IP TE        40     rt5                  -         rt1(4)\r
+rt6                  TE-IS        50     rt6                  -         rt8(4)\r
+rt7                  TE-IS        50     rt7                  -         rt8(4)\r
+rt3                  TE-IS        50     rt5                  -         rt1(4)\r
+rt4                  TE-IS        50     rt5                  -         rt1(4)\r
+10.0.255.6/32        IP TE        60     rt6                  -         rt6(4)\r
+10.0.255.7/32        IP TE        60     rt7                  -         rt7(4)\r
+10.0.255.3/32        IP TE        60     rt5                  -         rt3(4)\r
+10.0.255.4/32        IP TE        60     rt5                  -         rt4(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  40      -          rt5      16010          \r
+ 10.0.255.2/32  30      -          rt5      16020          \r
+ 10.0.255.3/32  60      -          rt5      16030          \r
+ 10.0.255.4/32  60      -          rt5      16040          \r
+ 10.0.255.5/32  20      -          rt5      implicit-null  \r
+ 10.0.255.6/32  60      -          rt6      implicit-null  \r
+ 10.0.255.7/32  60      -          rt7      implicit-null  \r
+ 10.0.255.8/32  0       -          -        -              \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)  \r
+ -----------------------------------------------------\r
+ 10.0.255.1/32  80      -          rt6      16010     \r
+                        -          rt7      16010     \r
+ 10.0.255.2/32  90      -          rt6      16020     \r
+                        -          rt7      16020     \r
+ 10.0.255.3/32  60      -          rt6      16030     \r
+                        -          rt7      16030     \r
+ 10.0.255.4/32  60      -          rt6      16040     \r
+                        -          rt7      16040     \r
+ 10.0.255.5/32  100     -          rt6      16050     \r
+                        -          rt7      16050     \r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt8                                                                   \r
+2001:db8::8/128      IP6 internal 0                                     rt8(4)\r
+rt5                  TE-IS        10     rt5                  -         rt8(4)\r
+rt2                  TE-IS        20     rt5                  -         rt5(4)\r
+2001:db8::5/128      IP6 internal 20     rt5                  -         rt5(4)\r
+rt1                  TE-IS        30     rt5                  -         rt2(4)\r
+2001:db8::2/128      IP6 internal 30     rt5                  -         rt2(4)\r
+2001:db8::1/128      IP6 internal 40     rt5                  -         rt1(4)\r
+rt6                  TE-IS        50     rt6                  -         rt8(4)\r
+rt7                  TE-IS        50     rt7                  -         rt8(4)\r
+rt3                  TE-IS        50     rt5                  -         rt1(4)\r
+rt4                  TE-IS        50     rt5                  -         rt1(4)\r
+2001:db8::6/128      IP6 internal 60     rt6                  -         rt6(4)\r
+2001:db8::7/128      IP6 internal 60     rt7                  -         rt7(4)\r
+2001:db8::3/128      IP6 internal 60     rt5                  -         rt3(4)\r
+2001:db8::4/128      IP6 internal 60     rt5                  -         rt4(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  40      -          rt5      16011          \r
+ 2001:db8::2/128  30      -          rt5      16021          \r
+ 2001:db8::3/128  60      -          rt5      16031          \r
+ 2001:db8::4/128  60      -          rt5      16041          \r
+ 2001:db8::5/128  20      -          rt5      implicit-null  \r
+ 2001:db8::6/128  60      -          rt6      implicit-null  \r
+ 2001:db8::7/128  60      -          rt7      implicit-null  \r
+ 2001:db8::8/128  0       -          -        -              \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)  \r
+ -------------------------------------------------------\r
+ 2001:db8::1/128  80      -          rt6      16011     \r
+                          -          rt7      16011     \r
+ 2001:db8::2/128  90      -          rt6      16021     \r
+                          -          rt7      16021     \r
+ 2001:db8::3/128  60      -          rt6      16031     \r
+                          -          rt7      16031     \r
+ 2001:db8::4/128  60      -          rt6      16041     \r
+                          -          rt7      16041     \r
+ 2001:db8::5/128  100     -          rt6      16051     \r
+                          -          rt7      16051     \r
+\r
+test# test isis topology 11 root rt3 lfa system-id rt5\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt3                                                                   \r
+10.0.255.3/32        IP internal  0                                     rt3(4)\r
+rt1                  TE-IS        10     rt1                  -         rt3(4)\r
+rt2                  TE-IS        10     rt2                  -         rt3(4)\r
+rt5                  TE-IS        10     rt5                  -         rt3(4)\r
+rt2                  pseudo_TE-IS 20     rt1                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+                                         rt5                  -         rt5(4)\r
+rt6                  TE-IS        20     rt5                  -         rt5(4)\r
+10.0.255.1/32        IP TE        20     rt1                  -         rt1(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.5/32        IP TE        20     rt5                  -         rt5(4)\r
+10.0.255.4/32        IP TE        30     rt2                  -         rt4(4)\r
+                                         rt5                  -         \r
+10.0.255.6/32        IP TE        30     rt5                  -         rt6(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  20      -          rt1      implicit-null  \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  0       -          -        -              \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+                        -          rt5      16040          \r
+ 10.0.255.5/32  20      -          rt5      implicit-null  \r
+ 10.0.255.6/32  30      -          rt5      16060          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)  \r
+ -----------------------------------------------------\r
+ 10.0.255.5/32  30      -          rt2      16050     \r
+ 10.0.255.6/32  30      -          rt2      16060     \r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt3                                                                   \r
+2001:db8::3/128      IP6 internal 0                                     rt3(4)\r
+rt1                  TE-IS        10     rt1                  -         rt3(4)\r
+rt2                  TE-IS        10     rt2                  -         rt3(4)\r
+rt5                  TE-IS        10     rt5                  -         rt3(4)\r
+rt2                  pseudo_TE-IS 20     rt1                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+                                         rt5                  -         rt5(4)\r
+rt6                  TE-IS        20     rt5                  -         rt5(4)\r
+2001:db8::1/128      IP6 internal 20     rt1                  -         rt1(4)\r
+2001:db8::2/128      IP6 internal 20     rt2                  -         rt2(4)\r
+2001:db8::5/128      IP6 internal 20     rt5                  -         rt5(4)\r
+2001:db8::4/128      IP6 internal 30     rt2                  -         rt4(4)\r
+                                         rt5                  -         \r
+2001:db8::6/128      IP6 internal 30     rt5                  -         rt6(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  20      -          rt1      implicit-null  \r
+ 2001:db8::2/128  20      -          rt2      implicit-null  \r
+ 2001:db8::3/128  0       -          -        -              \r
+ 2001:db8::4/128  30      -          rt2      16041          \r
+                          -          rt5      16041          \r
+ 2001:db8::5/128  20      -          rt5      implicit-null  \r
+ 2001:db8::6/128  30      -          rt5      16061          \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\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
+\r
+test# test isis topology 13 root rt4 lfa system-id rt3\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt4                                                                   \r
+10.0.255.4/32        IP internal  0                                     rt4(4)\r
+rt2                  TE-IS        10     rt2                  -         rt4(4)\r
+rt3                  TE-IS        10     rt3                  -         rt4(4)\r
+rt1                  TE-IS        20     rt2                  -         rt2(4)\r
+                                         rt3                  -         rt3(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt7                  TE-IS        30     rt3                  -         rt5(4)\r
+                                                                        rt6(4)\r
+10.0.255.1/32        IP TE        30     rt2                  -         rt1(4)\r
+                                         rt3                  -         \r
+10.0.255.5/32        IP TE        30     rt3                  -         rt5(4)\r
+10.0.255.6/32        IP TE        30     rt3                  -         rt6(4)\r
+10.0.255.7/32        IP TE        40     rt3                  -         rt7(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  30      -          rt2      16010          \r
+                        -          rt3      16010          \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  0       -          -        -              \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  30      -          rt3      16060          \r
+ 10.0.255.7/32  40      -          rt3      16070          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.3/32  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
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt4                                                                   \r
+rt2                  TE-IS        10     rt2                  -         rt4(4)\r
+rt3                  TE-IS        10     rt3                  -         rt4(4)\r
+rt5                  TE-IS        100    rt5                  -         rt4(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+test# test isis topology 14 root rt1 lfa system-id rt1 pseudonode-id 1\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        10     rt4                  -         rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt1                                                                   \r
+rt5                  TE-IS        20     rt4                  -         rt4(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.5/32        IP TE        30     rt4                  -         rt5(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)  \r
+ -----------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -         \r
+ 10.0.255.2/32  20      -          rt2      -         \r
+ 10.0.255.3/32  20      -          rt3      -         \r
+ 10.0.255.4/32  20      -          rt4      -         \r
+ 10.0.255.5/32  30      -          rt4      -         \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+2001:db8::1/128      IP6 internal 0                                     rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        10     rt4                  -         rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt1                                                                   \r
+rt5                  TE-IS        20     rt4                  -         rt4(4)\r
+2001:db8::3/128      IP6 internal 20     rt3                  -         rt3(4)\r
+2001:db8::4/128      IP6 internal 20     rt4                  -         rt4(4)\r
+2001:db8::2/128      IP6 internal 20     rt2                  -         rt2(4)\r
+2001:db8::5/128      IP6 internal 30     rt4                  -         rt5(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)  \r
+ -------------------------------------------------------\r
+ 2001:db8::1/128  0       -          -        -         \r
+ 2001:db8::2/128  20      -          rt2      -         \r
+ 2001:db8::3/128  20      -          rt3      -         \r
+ 2001:db8::4/128  20      -          rt4      -         \r
+ 2001:db8::5/128  30      -          rt4      -         \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+test# test isis topology 14 root rt1 lfa system-id rt2\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        10     rt4                  -         rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt1                                                                   \r
+rt5                  TE-IS        20     rt4                  -         rt4(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.5/32        IP TE        30     rt4                  -         rt5(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)  \r
+ -----------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -         \r
+ 10.0.255.2/32  20      -          rt2      -         \r
+ 10.0.255.3/32  20      -          rt3      -         \r
+ 10.0.255.4/32  20      -          rt4      -         \r
+ 10.0.255.5/32  30      -          rt4      -         \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)  \r
+ -----------------------------------------------------\r
+ 10.0.255.2/32  20      -          rt3      -         \r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+2001:db8::1/128      IP6 internal 0                                     rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        10     rt4                  -         rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt1                                                                   \r
+rt5                  TE-IS        20     rt4                  -         rt4(4)\r
+2001:db8::3/128      IP6 internal 20     rt3                  -         rt3(4)\r
+2001:db8::4/128      IP6 internal 20     rt4                  -         rt4(4)\r
+2001:db8::2/128      IP6 internal 20     rt2                  -         rt2(4)\r
+2001:db8::5/128      IP6 internal 30     rt4                  -         rt5(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)  \r
+ -------------------------------------------------------\r
+ 2001:db8::1/128  0       -          -        -         \r
+ 2001:db8::2/128  20      -          rt2      -         \r
+ 2001:db8::3/128  20      -          rt3      -         \r
+ 2001:db8::4/128  20      -          rt4      -         \r
+ 2001:db8::5/128  30      -          rt4      -         \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)  \r
+ -------------------------------------------------------\r
+ 2001:db8::2/128  20      -          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
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+10.0.255.5/32        IP internal  0                                     rt5(4)\r
+rt4                  TE-IS        10     rt4                  -         rt5(4)\r
+rt1                  pseudo_TE-IS 20     rt4                  -         rt4(4)\r
+rt1                  TE-IS        20     rt4                  -         rt1(2)\r
+rt3                  TE-IS        20     rt4                  -         rt1(2)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+rt2                  TE-IS        30     rt4                  -         rt1(4)\r
+                                                                        rt3(4)\r
+10.0.255.1/32        IP TE        30     rt4                  -         rt1(4)\r
+10.0.255.3/32        IP TE        30     rt4                  -         rt3(4)\r
+10.0.255.2/32        IP TE        40     rt4                  -         rt2(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)  \r
+ -----------------------------------------------------\r
+ 10.0.255.1/32  30      -          rt4      -         \r
+ 10.0.255.2/32  40      -          rt4      -         \r
+ 10.0.255.3/32  30      -          rt4      -         \r
+ 10.0.255.4/32  20      -          rt4      -         \r
+ 10.0.255.5/32  0       -          -        -         \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)  \r
+ -----------------------------------------------------\r
+ 10.0.255.1/32  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
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+2001:db8::5/128      IP6 internal 0                                     rt5(4)\r
+rt4                  TE-IS        10     rt4                  -         rt5(4)\r
+rt1                  pseudo_TE-IS 20     rt4                  -         rt4(4)\r
+rt1                  TE-IS        20     rt4                  -         rt1(2)\r
+rt3                  TE-IS        20     rt4                  -         rt1(2)\r
+2001:db8::4/128      IP6 internal 20     rt4                  -         rt4(4)\r
+rt2                  TE-IS        30     rt4                  -         rt1(4)\r
+                                                                        rt3(4)\r
+2001:db8::1/128      IP6 internal 30     rt4                  -         rt1(4)\r
+2001:db8::3/128      IP6 internal 30     rt4                  -         rt3(4)\r
+2001:db8::2/128      IP6 internal 40     rt4                  -         rt2(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)  \r
+ -------------------------------------------------------\r
+ 2001:db8::1/128  30      -          rt4      -         \r
+ 2001:db8::2/128  40      -          rt4      -         \r
+ 2001:db8::3/128  30      -          rt4      -         \r
+ 2001:db8::4/128  20      -          rt4      -         \r
+ 2001:db8::5/128  0       -          -        -         \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\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
+\r
+test# \r
+test# test isis topology 1 root rt1 remote-lfa system-id rt2\r
+P-space (self):\r
+ rt3\r
+ rt5\r
+\r
+P-space (rt3):\r
+ rt3\r
+ rt5\r
+ rt6\r
+\r
+Q-space:\r
+ rt2\r
+ rt4\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt3                  -         rt5(4)\r
+10.0.255.5/32        IP TE        30     rt3                  -         rt5(4)\r
+rt4                  TE-IS        40     rt3                  -         rt6(4)\r
+10.0.255.6/32        IP TE        40     rt3                  -         rt6(4)\r
+rt2                  TE-IS        50     rt3                  -         rt4(4)\r
+10.0.255.4/32        IP TE        50     rt3                  -         rt4(4)\r
+10.0.255.2/32        IP TE        60     rt3                  -         rt2(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt2                  -         rt4(4)\r
+                                         rt3                  -         rt5(4)\r
+10.0.255.4/32        IP TE        30     rt2                  -         rt4(4)\r
+10.0.255.5/32        IP TE        30     rt3                  -         rt5(4)\r
+10.0.255.6/32        IP TE        40     rt2                  -         rt6(4)\r
+                                         rt3                  -         \r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  40      -          rt2      16060          \r
+                        -          rt3      16060          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)     \r
+ --------------------------------------------------------\r
+ 10.0.255.2/32  60      -          rt3      50600/16020  \r
+ 10.0.255.4/32  50      -          rt3      50600/16040  \r
+\r
+P-space (self):\r
+ rt3\r
+ rt5\r
+\r
+P-space (rt3):\r
+ rt3\r
+ rt5\r
+ rt6\r
+\r
+Q-space:\r
+ rt2\r
+ rt4\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+2001:db8::1/128      IP6 internal 0                                     rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+2001:db8::3/128      IP6 internal 20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt3                  -         rt5(4)\r
+2001:db8::5/128      IP6 internal 30     rt3                  -         rt5(4)\r
+rt4                  TE-IS        40     rt3                  -         rt6(4)\r
+2001:db8::6/128      IP6 internal 40     rt3                  -         rt6(4)\r
+rt2                  TE-IS        50     rt3                  -         rt4(4)\r
+2001:db8::4/128      IP6 internal 50     rt3                  -         rt4(4)\r
+2001:db8::2/128      IP6 internal 60     rt3                  -         rt2(4)\r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+2001:db8::1/128      IP6 internal 0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+2001:db8::2/128      IP6 internal 20     rt2                  -         rt2(4)\r
+2001:db8::3/128      IP6 internal 20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt2                  -         rt4(4)\r
+                                         rt3                  -         rt5(4)\r
+2001:db8::4/128      IP6 internal 30     rt2                  -         rt4(4)\r
+2001:db8::5/128      IP6 internal 30     rt3                  -         rt5(4)\r
+2001:db8::6/128      IP6 internal 40     rt2                  -         rt6(4)\r
+                                         rt3                  -         \r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  0       -          -        -              \r
+ 2001:db8::2/128  20      -          rt2      implicit-null  \r
+ 2001:db8::3/128  20      -          rt3      implicit-null  \r
+ 2001:db8::4/128  30      -          rt2      16041          \r
+ 2001:db8::5/128  30      -          rt3      16051          \r
+ 2001:db8::6/128  40      -          rt2      16061          \r
+                          -          rt3      16061          \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)     \r
+ ----------------------------------------------------------\r
+ 2001:db8::2/128  60      -          rt3      50600/16021  \r
+ 2001:db8::4/128  50      -          rt3      50600/16041  \r
+\r
+test# test isis topology 2 root rt5 remote-lfa system-id rt1 pseudonode-id 1\r
+P-space (self):\r
+ rt6\r
+\r
+P-space (rt3):\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+\r
+P-space (rt6):\r
+ rt4\r
+ rt6\r
+\r
+Q-space:\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+10.0.255.5/32        IP internal  0                                     rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt4                  TE-IS        20     rt6                  -         rt6(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt1                  pseudo_TE-IS 30     rt6                  -         rt4(4)\r
+rt1                  TE-IS        30     rt6                  -         rt1(2)\r
+10.0.255.4/32        IP TE        30     rt6                  -         rt4(4)\r
+rt3                  TE-IS        40     rt3                  -         rt5(4)\r
+10.0.255.1/32        IP TE        40     rt6                  -         rt1(4)\r
+rt2                  TE-IS        45     rt6                  -         rt1(4)\r
+10.0.255.3/32        IP TE        50     rt3                  -         rt3(4)\r
+10.0.255.2/32        IP TE        55     rt6                  -         rt2(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+10.0.255.5/32        IP internal  0                                     rt5(4)\r
+rt1                  TE-IS        10     rt1                  -         rt5(4)\r
+rt4                  TE-IS        10     rt4                  -         rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt1                  pseudo_TE-IS 20     rt1                  -         rt1(4)\r
+                                         rt4                  -         rt4(4)\r
+10.0.255.1/32        IP TE        20     rt1                  -         rt1(4)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt2                  TE-IS        25     rt1                  -         rt1(4)\r
+10.0.255.2/32        IP TE        35     rt1                  -         rt2(4)\r
+rt3                  TE-IS        40     rt3                  -         rt5(4)\r
+                                         rt1                  -         rt1(4)\r
+10.0.255.3/32        IP TE        50     rt3                  -         rt3(4)\r
+                                         rt1                  -         \r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  20      -          rt1      implicit-null  \r
+ 10.0.255.2/32  35      -          rt1      16020          \r
+ 10.0.255.3/32  50      -          rt3      implicit-null  \r
+                        -          rt1      implicit-null  \r
+ 10.0.255.4/32  20      -          rt4      implicit-null  \r
+ 10.0.255.5/32  0       -          -        -              \r
+ 10.0.255.6/32  20      -          rt6      implicit-null  \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)     \r
+ --------------------------------------------------------\r
+ 10.0.255.1/32  40      -          rt6      50400/16010  \r
+ 10.0.255.2/32  55      -          rt6      50400/16020  \r
+ 10.0.255.4/32  30      -          rt6      50400/16040  \r
+\r
+P-space (self):\r
+ rt6\r
+\r
+P-space (rt3):\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+\r
+P-space (rt6):\r
+ rt4\r
+ rt6\r
+\r
+Q-space:\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+2001:db8::5/128      IP6 internal 0                                     rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt4                  TE-IS        20     rt6                  -         rt6(4)\r
+2001:db8::6/128      IP6 internal 20     rt6                  -         rt6(4)\r
+rt1                  pseudo_TE-IS 30     rt6                  -         rt4(4)\r
+rt1                  TE-IS        30     rt6                  -         rt1(2)\r
+2001:db8::4/128      IP6 internal 30     rt6                  -         rt4(4)\r
+rt3                  TE-IS        40     rt3                  -         rt5(4)\r
+2001:db8::1/128      IP6 internal 40     rt6                  -         rt1(4)\r
+rt2                  TE-IS        45     rt6                  -         rt1(4)\r
+2001:db8::3/128      IP6 internal 50     rt3                  -         rt3(4)\r
+2001:db8::2/128      IP6 internal 55     rt6                  -         rt2(4)\r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+2001:db8::5/128      IP6 internal 0                                     rt5(4)\r
+rt1                  TE-IS        10     rt1                  -         rt5(4)\r
+rt4                  TE-IS        10     rt4                  -         rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt1                  pseudo_TE-IS 20     rt1                  -         rt1(4)\r
+                                         rt4                  -         rt4(4)\r
+2001:db8::1/128      IP6 internal 20     rt1                  -         rt1(4)\r
+2001:db8::4/128      IP6 internal 20     rt4                  -         rt4(4)\r
+2001:db8::6/128      IP6 internal 20     rt6                  -         rt6(4)\r
+rt2                  TE-IS        25     rt1                  -         rt1(4)\r
+2001:db8::2/128      IP6 internal 35     rt1                  -         rt2(4)\r
+rt3                  TE-IS        40     rt3                  -         rt5(4)\r
+                                         rt1                  -         rt1(4)\r
+2001:db8::3/128      IP6 internal 50     rt3                  -         rt3(4)\r
+                                         rt1                  -         \r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  20      -          rt1      implicit-null  \r
+ 2001:db8::2/128  35      -          rt1      16021          \r
+ 2001:db8::3/128  50      -          rt3      implicit-null  \r
+                          -          rt1      implicit-null  \r
+ 2001:db8::4/128  20      -          rt4      implicit-null  \r
+ 2001:db8::5/128  0       -          -        -              \r
+ 2001:db8::6/128  20      -          rt6      implicit-null  \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)     \r
+ ----------------------------------------------------------\r
+ 2001:db8::1/128  40      -          rt6      50400/16011  \r
+ 2001:db8::2/128  55      -          rt6      50400/16021  \r
+ 2001:db8::4/128  30      -          rt6      50400/16041  \r
+\r
+test# test isis topology 3 root rt5 remote-lfa system-id rt4 ipv4-only\r
+P-space (self):\r
+ rt6\r
+\r
+P-space (rt3):\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+P-space (rt6):\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+Q-space:\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+10.0.255.5/32        IP internal  0                                     rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt4                  TE-IS        20     rt6                  -         rt6(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt3                  TE-IS        30     rt3                  -         rt5(4)\r
+rt2                  TE-IS        30     rt6                  -         rt4(4)\r
+10.0.255.4/32        IP TE        30     rt6                  -         rt4(4)\r
+rt1                  TE-IS        40     rt3                  -         rt3(4)\r
+                                         rt6                  -         rt2(4)\r
+10.0.255.3/32        IP TE        40     rt3                  -         rt3(4)\r
+10.0.255.2/32        IP TE        40     rt6                  -         rt2(4)\r
+10.0.255.1/32        IP TE        50     rt3                  -         rt1(4)\r
+                                         rt6                  -         \r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+10.0.255.5/32        IP internal  0                                     rt5(4)\r
+rt4                  TE-IS        10     rt4                  -         rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt2                  TE-IS        20     rt4                  -         rt4(4)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt3                  TE-IS        30     rt3                  -         rt5(4)\r
+                                         rt4                  -         rt2(4)\r
+rt1                  TE-IS        30     rt4                  -         rt2(4)\r
+10.0.255.2/32        IP TE        30     rt4                  -         rt2(4)\r
+10.0.255.3/32        IP TE        40     rt3                  -         rt3(4)\r
+                                         rt4                  -         \r
+10.0.255.1/32        IP TE        40     rt4                  -         rt1(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  40      -          rt4      16010          \r
+ 10.0.255.2/32  30      -          rt4      16020          \r
+ 10.0.255.3/32  40      -          rt3      implicit-null  \r
+                        -          rt4      implicit-null  \r
+ 10.0.255.4/32  20      -          rt4      implicit-null  \r
+ 10.0.255.5/32  0       -          -        -              \r
+ 10.0.255.6/32  20      -          rt6      implicit-null  \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)  \r
+ -----------------------------------------------------\r
+ 10.0.255.1/32  40      -          rt3      16010     \r
+                        -          rt6      16010     \r
+ 10.0.255.2/32  30      -          rt3      16020     \r
+                        -          rt6      16020     \r
+ 10.0.255.4/32  20      -          rt3      16040     \r
+                        -          rt6      16040     \r
+\r
+test# test isis topology 3 root rt5 remote-lfa system-id rt3 ipv4-only\r
+P-space (self):\r
+ rt1\r
+ rt2\r
+ rt4\r
+ rt6\r
+\r
+P-space (rt4):\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+P-space (rt6):\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+Q-space:\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+10.0.255.5/32        IP internal  0                                     rt5(4)\r
+rt4                  TE-IS        10     rt4                  -         rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt2                  TE-IS        20     rt4                  -         rt4(4)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt1                  TE-IS        30     rt4                  -         rt2(4)\r
+rt3                  TE-IS        30     rt4                  -         rt2(4)\r
+10.0.255.2/32        IP TE        30     rt4                  -         rt2(4)\r
+10.0.255.1/32        IP TE        40     rt4                  -         rt1(4)\r
+10.0.255.3/32        IP TE        40     rt4                  -         rt3(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+10.0.255.5/32        IP internal  0                                     rt5(4)\r
+rt4                  TE-IS        10     rt4                  -         rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt2                  TE-IS        20     rt4                  -         rt4(4)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt3                  TE-IS        30     rt3                  -         rt5(4)\r
+                                         rt4                  -         rt2(4)\r
+rt1                  TE-IS        30     rt4                  -         rt2(4)\r
+10.0.255.2/32        IP TE        30     rt4                  -         rt2(4)\r
+10.0.255.3/32        IP TE        40     rt3                  -         rt3(4)\r
+                                         rt4                  -         \r
+10.0.255.1/32        IP TE        40     rt4                  -         rt1(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  40      -          rt4      16010          \r
+ 10.0.255.2/32  30      -          rt4      16020          \r
+ 10.0.255.3/32  40      -          rt3      implicit-null  \r
+                        -          rt4      implicit-null  \r
+ 10.0.255.4/32  20      -          rt4      implicit-null  \r
+ 10.0.255.5/32  0       -          -        -              \r
+ 10.0.255.6/32  20      -          rt6      implicit-null  \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+test# test isis topology 5 root rt1 remote-lfa system-id rt2 ipv4-only\r
+P-space (self):\r
+ rt3\r
+ rt5\r
+ rt7\r
+\r
+P-space (rt3):\r
+ rt3\r
+ rt5\r
+ rt7\r
+ rt8\r
+\r
+Q-space:\r
+ rt2\r
+ rt4\r
+ rt6\r
+ rt8\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt7                  TE-IS        30     rt3                  -         rt5(4)\r
+10.0.255.5/32        IP TE        30     rt3                  -         rt5(4)\r
+rt8                  TE-IS        40     rt3                  -         rt7(4)\r
+10.0.255.7/32        IP TE        40     rt3                  -         rt7(4)\r
+rt6                  TE-IS        50     rt3                  -         rt8(4)\r
+10.0.255.8/32        IP TE        50     rt3                  -         rt8(4)\r
+rt4                  TE-IS        60     rt3                  -         rt6(4)\r
+10.0.255.6/32        IP TE        60     rt3                  -         rt6(4)\r
+rt2                  TE-IS        70     rt3                  -         rt4(4)\r
+10.0.255.4/32        IP TE        70     rt3                  -         rt4(4)\r
+10.0.255.2/32        IP TE        80     rt3                  -         rt2(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt2                  -         rt4(4)\r
+rt7                  TE-IS        30     rt3                  -         rt5(4)\r
+10.0.255.4/32        IP TE        30     rt2                  -         rt4(4)\r
+10.0.255.5/32        IP TE        30     rt3                  -         rt5(4)\r
+rt8                  TE-IS        40     rt2                  -         rt6(4)\r
+                                         rt3                  -         rt7(4)\r
+10.0.255.6/32        IP TE        40     rt2                  -         rt6(4)\r
+10.0.255.7/32        IP TE        40     rt3                  -         rt7(4)\r
+10.0.255.8/32        IP TE        50     rt2                  -         rt8(4)\r
+                                         rt3                  -         \r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  40      -          rt2      16060          \r
+ 10.0.255.7/32  40      -          rt3      16070          \r
+ 10.0.255.8/32  50      -          rt2      16080          \r
+                        -          rt3      16080          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)     \r
+ --------------------------------------------------------\r
+ 10.0.255.2/32  80      -          rt3      50800/16020  \r
+ 10.0.255.4/32  70      -          rt3      50800/16040  \r
+ 10.0.255.6/32  60      -          rt3      50800/16060  \r
+\r
+test# test isis topology 6 root rt4 remote-lfa system-id rt3 ipv4-only\r
+P-space (self):\r
+ rt2\r
+ rt5\r
+ rt6\r
+ rt7\r
+ rt8\r
+\r
+P-space (rt2):\r
+ rt1\r
+ rt2\r
+\r
+P-space (rt6):\r
+ rt5\r
+ rt6\r
+ rt7\r
+ rt8\r
+\r
+Q-space:\r
+ rt1\r
+ rt3\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt4                                                                   \r
+10.0.255.4/32        IP internal  0                                     rt4(4)\r
+rt2                  TE-IS        10     rt2                  -         rt4(4)\r
+rt6                  TE-IS        10     rt6                  -         rt4(4)\r
+rt1                  TE-IS        20     rt2                  -         rt2(4)\r
+rt5                  TE-IS        20     rt6                  -         rt6(4)\r
+rt8                  TE-IS        20     rt6                  -         rt6(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt3                  TE-IS        30     rt2                  -         rt1(4)\r
+rt7                  TE-IS        30     rt6                  -         rt5(4)\r
+                                                                        rt8(4)\r
+10.0.255.1/32        IP TE        30     rt2                  -         rt1(4)\r
+10.0.255.5/32        IP TE        30     rt6                  -         rt5(4)\r
+10.0.255.8/32        IP TE        30     rt6                  -         rt8(4)\r
+10.0.255.3/32        IP TE        40     rt2                  -         rt3(4)\r
+10.0.255.7/32        IP TE        40     rt6                  -         rt7(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt4                                                                   \r
+10.0.255.4/32        IP internal  0                                     rt4(4)\r
+rt2                  TE-IS        10     rt2                  -         rt4(4)\r
+rt3                  TE-IS        10     rt3                  -         rt4(4)\r
+rt6                  TE-IS        10     rt6                  -         rt4(4)\r
+rt1                  TE-IS        20     rt2                  -         rt2(4)\r
+                                         rt3                  -         rt3(4)\r
+rt5                  TE-IS        20     rt6                  -         rt6(4)\r
+rt8                  TE-IS        20     rt6                  -         rt6(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt7                  TE-IS        30     rt6                  -         rt5(4)\r
+                                                                        rt8(4)\r
+10.0.255.1/32        IP TE        30     rt2                  -         rt1(4)\r
+                                         rt3                  -         \r
+10.0.255.5/32        IP TE        30     rt6                  -         rt5(4)\r
+10.0.255.8/32        IP TE        30     rt6                  -         rt8(4)\r
+10.0.255.7/32        IP TE        40     rt6                  -         rt7(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  30      -          rt2      16010          \r
+                        -          rt3      16010          \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  0       -          -        -              \r
+ 10.0.255.5/32  30      -          rt6      16050          \r
+ 10.0.255.6/32  20      -          rt6      implicit-null  \r
+ 10.0.255.7/32  40      -          rt6      16070          \r
+ 10.0.255.8/32  30      -          rt6      16080          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)     \r
+ --------------------------------------------------------\r
+ 10.0.255.3/32  40      -          rt2      50100/16030  \r
+\r
+test# test isis topology 7 root rt11 remote-lfa system-id rt8 ipv4-only\r
+P-space (self):\r
+ rt10\r
+ rt12\r
+\r
+P-space (rt10):\r
+ rt1\r
+ rt4\r
+ rt7\r
+ rt10\r
+\r
+P-space (rt12):\r
+ rt9\r
+ rt12\r
+\r
+Q-space:\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt5\r
+ rt6\r
+ rt7\r
+ rt8\r
+ rt9\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt11                                                                  \r
+10.0.255.11/32       IP internal  0                                     rt11(4)\r
+rt10                 TE-IS        10     rt10                 -         rt11(4)\r
+rt12                 TE-IS        10     rt12                 -         rt11(4)\r
+rt9                  TE-IS        20     rt12                 -         rt12(4)\r
+10.0.255.10/32       IP TE        20     rt10                 -         rt10(4)\r
+10.0.255.12/32       IP TE        20     rt12                 -         rt12(4)\r
+rt7                  TE-IS        30     rt10                 -         rt10(4)\r
+rt8                  TE-IS        30     rt12                 -         rt9(4)\r
+10.0.255.9/32        IP TE        30     rt12                 -         rt9(4)\r
+rt4                  TE-IS        40     rt10                 -         rt7(4)\r
+rt5                  TE-IS        40     rt12                 -         rt8(4)\r
+10.0.255.7/32        IP TE        40     rt10                 -         rt7(4)\r
+10.0.255.8/32        IP TE        40     rt12                 -         rt8(4)\r
+rt6                  TE-IS        50     rt12                 -         rt9(4)\r
+                                                                        rt5(4)\r
+rt1                  TE-IS        50     rt10                 -         rt4(4)\r
+rt2                  TE-IS        50     rt12                 -         rt5(4)\r
+10.0.255.4/32        IP TE        50     rt10                 -         rt4(4)\r
+10.0.255.5/32        IP TE        50     rt12                 -         rt5(4)\r
+rt3                  TE-IS        60     rt12                 -         rt6(4)\r
+                                                                        rt2(4)\r
+10.0.255.6/32        IP TE        60     rt12                 -         rt6(4)\r
+10.0.255.1/32        IP TE        60     rt10                 -         rt1(4)\r
+10.0.255.2/32        IP TE        60     rt12                 -         rt2(4)\r
+10.0.255.3/32        IP TE        70     rt12                 -         rt3(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt11                                                                  \r
+10.0.255.11/32       IP internal  0                                     rt11(4)\r
+rt8                  TE-IS        10     rt8                  -         rt11(4)\r
+rt10                 TE-IS        10     rt10                 -         rt11(4)\r
+rt12                 TE-IS        10     rt12                 -         rt11(4)\r
+rt5                  TE-IS        20     rt8                  -         rt8(4)\r
+rt7                  TE-IS        20     rt8                  -         rt8(4)\r
+rt9                  TE-IS        20     rt8                  -         rt8(4)\r
+                                         rt12                 -         rt12(4)\r
+10.0.255.8/32        IP TE        20     rt8                  -         rt8(4)\r
+10.0.255.10/32       IP TE        20     rt10                 -         rt10(4)\r
+10.0.255.12/32       IP TE        20     rt12                 -         rt12(4)\r
+rt2                  TE-IS        30     rt8                  -         rt5(4)\r
+rt4                  TE-IS        30     rt8                  -         rt5(4)\r
+                                                                        rt7(4)\r
+rt6                  TE-IS        30     rt8                  -         rt5(4)\r
+10.0.255.5/32        IP TE        30     rt8                  -         rt5(4)\r
+10.0.255.7/32        IP TE        30     rt8                  -         rt7(4)\r
+10.0.255.9/32        IP TE        30     rt8                  -         rt9(4)\r
+                                         rt12                 -         \r
+rt3                  TE-IS        40     rt8                  -         rt2(4)\r
+                                                                        rt6(4)\r
+rt1                  TE-IS        40     rt8                  -         rt4(4)\r
+10.0.255.2/32        IP TE        40     rt8                  -         rt2(4)\r
+10.0.255.4/32        IP TE        40     rt8                  -         rt4(4)\r
+10.0.255.6/32        IP TE        40     rt8                  -         rt6(4)\r
+10.0.255.3/32        IP TE        50     rt8                  -         rt3(4)\r
+10.0.255.1/32        IP TE        50     rt8                  -         rt1(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)       \r
+ -----------------------------------------------------------\r
+ 10.0.255.1/32   50      -          rt8      16010          \r
+ 10.0.255.2/32   40      -          rt8      16020          \r
+ 10.0.255.3/32   50      -          rt8      16030          \r
+ 10.0.255.4/32   40      -          rt8      16040          \r
+ 10.0.255.5/32   30      -          rt8      16050          \r
+ 10.0.255.6/32   40      -          rt8      16060          \r
+ 10.0.255.7/32   30      -          rt8      16070          \r
+ 10.0.255.8/32   20      -          rt8      implicit-null  \r
+ 10.0.255.9/32   30      -          rt8      16090          \r
+                         -          rt12     16090          \r
+ 10.0.255.10/32  20      -          rt10     implicit-null  \r
+ 10.0.255.11/32  0       -          -        -              \r
+ 10.0.255.12/32  20      -          rt12     implicit-null  \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)     \r
+ --------------------------------------------------------\r
+ 10.0.255.1/32  50      -          rt10     16010        \r
+ 10.0.255.2/32  60      -          rt12     50900/16020  \r
+ 10.0.255.3/32  70      -          rt12     50900/16030  \r
+ 10.0.255.4/32  40      -          rt10     16040        \r
+ 10.0.255.5/32  50      -          rt12     50900/16050  \r
+ 10.0.255.6/32  60      -          rt12     50900/16060  \r
+ 10.0.255.7/32  30      -          rt10     16070        \r
+ 10.0.255.8/32  40      -          rt12     50900/16080  \r
+\r
+test# test isis topology 7 root rt6 remote-lfa system-id rt5 ipv4-only\r
+P-space (self):\r
+ rt3\r
+\r
+P-space (rt3):\r
+ rt2\r
+ rt3\r
+\r
+P-space (rt9):\r
+ rt1\r
+ rt2\r
+ rt4\r
+ rt5\r
+ rt7\r
+ rt8\r
+ rt9\r
+ rt10\r
+ rt11\r
+ rt12\r
+\r
+Q-space:\r
+ rt1\r
+ rt2\r
+ rt4\r
+ rt5\r
+ rt7\r
+ rt8\r
+ rt9\r
+ rt10\r
+ rt11\r
+ rt12\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt6                                                                   \r
+10.0.255.6/32        IP internal  0                                     rt6(4)\r
+rt3                  TE-IS        10     rt3                  -         rt6(4)\r
+rt2                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt9                  TE-IS        30     rt9                  -         rt6(4)\r
+rt5                  TE-IS        30     rt3                  -         rt2(4)\r
+10.0.255.2/32        IP TE        30     rt3                  -         rt2(4)\r
+rt8                  TE-IS        40     rt9                  -         rt9(4)\r
+                                         rt3                  -         rt5(4)\r
+rt12                 TE-IS        40     rt9                  -         rt9(4)\r
+rt4                  TE-IS        40     rt3                  -         rt5(4)\r
+10.0.255.9/32        IP TE        40     rt9                  -         rt9(4)\r
+10.0.255.5/32        IP TE        40     rt3                  -         rt5(4)\r
+rt7                  TE-IS        50     rt9                  -         rt8(4)\r
+                                         rt3                  -         rt4(4)\r
+rt11                 TE-IS        50     rt9                  -         rt8(4)\r
+                                         rt3                  -         rt12(4)\r
+rt1                  TE-IS        50     rt3                  -         rt4(4)\r
+10.0.255.8/32        IP TE        50     rt9                  -         rt8(4)\r
+                                         rt3                  -         \r
+10.0.255.12/32       IP TE        50     rt9                  -         rt12(4)\r
+10.0.255.4/32        IP TE        50     rt3                  -         rt4(4)\r
+rt10                 TE-IS        60     rt9                  -         rt11(4)\r
+                                         rt3                  -         \r
+10.0.255.7/32        IP TE        60     rt9                  -         rt7(4)\r
+                                         rt3                  -         \r
+10.0.255.11/32       IP TE        60     rt9                  -         rt11(4)\r
+                                         rt3                  -         \r
+10.0.255.1/32        IP TE        60     rt3                  -         rt1(4)\r
+10.0.255.10/32       IP TE        70     rt9                  -         rt10(4)\r
+                                         rt3                  -         \r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt6                                                                   \r
+10.0.255.6/32        IP internal  0                                     rt6(4)\r
+rt3                  TE-IS        10     rt3                  -         rt6(4)\r
+rt5                  TE-IS        10     rt5                  -         rt6(4)\r
+rt2                  TE-IS        20     rt3                  -         rt3(4)\r
+                                         rt5                  -         rt5(4)\r
+rt4                  TE-IS        20     rt5                  -         rt5(4)\r
+rt8                  TE-IS        20     rt5                  -         rt5(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+10.0.255.5/32        IP TE        20     rt5                  -         rt5(4)\r
+rt9                  TE-IS        30     rt9                  -         rt6(4)\r
+                                         rt5                  -         rt8(4)\r
+rt1                  TE-IS        30     rt5                  -         rt4(4)\r
+rt7                  TE-IS        30     rt5                  -         rt4(4)\r
+                                                                        rt8(4)\r
+rt11                 TE-IS        30     rt5                  -         rt8(4)\r
+10.0.255.2/32        IP TE        30     rt3                  -         rt2(4)\r
+                                         rt5                  -         \r
+10.0.255.4/32        IP TE        30     rt5                  -         rt4(4)\r
+10.0.255.8/32        IP TE        30     rt5                  -         rt8(4)\r
+rt12                 TE-IS        40     rt9                  -         rt9(4)\r
+                                         rt5                  -         rt11(4)\r
+rt10                 TE-IS        40     rt5                  -         rt11(4)\r
+10.0.255.9/32        IP TE        40     rt9                  -         rt9(4)\r
+                                         rt5                  -         \r
+10.0.255.1/32        IP TE        40     rt5                  -         rt1(4)\r
+10.0.255.7/32        IP TE        40     rt5                  -         rt7(4)\r
+10.0.255.11/32       IP TE        40     rt5                  -         rt11(4)\r
+10.0.255.12/32       IP TE        50     rt9                  -         rt12(4)\r
+                                         rt5                  -         \r
+10.0.255.10/32       IP TE        50     rt5                  -         rt10(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)       \r
+ -----------------------------------------------------------\r
+ 10.0.255.1/32   40      -          rt5      16010          \r
+ 10.0.255.2/32   30      -          rt3      16020          \r
+                         -          rt5      16020          \r
+ 10.0.255.3/32   20      -          rt3      implicit-null  \r
+ 10.0.255.4/32   30      -          rt5      16040          \r
+ 10.0.255.5/32   20      -          rt5      implicit-null  \r
+ 10.0.255.6/32   0       -          -        -              \r
+ 10.0.255.7/32   40      -          rt5      16070          \r
+ 10.0.255.8/32   30      -          rt5      16080          \r
+ 10.0.255.9/32   40      -          rt9      implicit-null  \r
+                         -          rt5      implicit-null  \r
+ 10.0.255.10/32  50      -          rt5      16100          \r
+ 10.0.255.11/32  40      -          rt5      16110          \r
+ 10.0.255.12/32  50      -          rt9      16120          \r
+                         -          rt5      16120          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)  \r
+ ------------------------------------------------------\r
+ 10.0.255.1/32   70      -          rt9      16010     \r
+ 10.0.255.4/32   60      -          rt9      16040     \r
+ 10.0.255.5/32   50      -          rt9      16050     \r
+ 10.0.255.7/32   50      -          rt9      16070     \r
+ 10.0.255.8/32   40      -          rt9      16080     \r
+ 10.0.255.10/32  60      -          rt9      16100     \r
+ 10.0.255.11/32  50      -          rt9      16110     \r
+\r
+test# test isis topology 8 root rt2 remote-lfa system-id rt5 ipv4-only\r
+P-space (self):\r
+ rt1\r
+ rt3\r
+ rt4\r
+ rt7\r
+ rt10\r
+\r
+P-space (rt1):\r
+ rt1\r
+ rt4\r
+ rt7\r
+ rt10\r
+\r
+P-space (rt3):\r
+ rt3\r
+ rt6\r
+\r
+Q-space:\r
+ rt5\r
+ rt6\r
+ rt8\r
+ rt9\r
+ rt11\r
+ rt12\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt2                                                                   \r
+10.0.255.2/32        IP internal  0                                     rt2(4)\r
+rt1                  TE-IS        10     rt1                  -         rt2(4)\r
+rt3                  TE-IS        10     rt3                  -         rt2(4)\r
+rt4                  TE-IS        20     rt1                  -         rt1(4)\r
+rt6                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.1/32        IP TE        20     rt1                  -         rt1(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt7                  TE-IS        30     rt1                  -         rt4(4)\r
+rt5                  TE-IS        30     rt3                  -         rt6(4)\r
+10.0.255.4/32        IP TE        30     rt1                  -         rt4(4)\r
+10.0.255.6/32        IP TE        30     rt3                  -         rt6(4)\r
+rt10                 TE-IS        40     rt1                  -         rt7(4)\r
+rt8                  TE-IS        40     rt3                  -         rt5(4)\r
+10.0.255.7/32        IP TE        40     rt1                  -         rt7(4)\r
+10.0.255.5/32        IP TE        40     rt3                  -         rt5(4)\r
+rt9                  TE-IS        50     rt3                  -         rt8(4)\r
+rt11                 TE-IS        50     rt3                  -         rt8(4)\r
+10.0.255.10/32       IP TE        50     rt1                  -         rt10(4)\r
+10.0.255.8/32        IP TE        50     rt3                  -         rt8(4)\r
+rt12                 TE-IS        60     rt3                  -         rt9(4)\r
+                                                                        rt11(4)\r
+10.0.255.9/32        IP TE        60     rt3                  -         rt9(4)\r
+10.0.255.11/32       IP TE        60     rt3                  -         rt11(4)\r
+10.0.255.12/32       IP TE        70     rt3                  -         rt12(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt2                                                                   \r
+10.0.255.2/32        IP internal  0                                     rt2(4)\r
+rt1                  TE-IS        10     rt1                  -         rt2(4)\r
+rt3                  TE-IS        10     rt3                  -         rt2(4)\r
+rt5                  TE-IS        10     rt5                  -         rt2(4)\r
+rt4                  TE-IS        20     rt1                  -         rt1(4)\r
+rt6                  TE-IS        20     rt3                  -         rt3(4)\r
+                                         rt5                  -         rt5(4)\r
+rt8                  TE-IS        20     rt5                  -         rt5(4)\r
+10.0.255.1/32        IP TE        20     rt1                  -         rt1(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+10.0.255.5/32        IP TE        20     rt5                  -         rt5(4)\r
+rt7                  TE-IS        30     rt1                  -         rt4(4)\r
+rt9                  TE-IS        30     rt5                  -         rt8(4)\r
+rt11                 TE-IS        30     rt5                  -         rt8(4)\r
+10.0.255.4/32        IP TE        30     rt1                  -         rt4(4)\r
+10.0.255.6/32        IP TE        30     rt3                  -         rt6(4)\r
+                                         rt5                  -         \r
+10.0.255.8/32        IP TE        30     rt5                  -         rt8(4)\r
+rt10                 TE-IS        40     rt1                  -         rt7(4)\r
+rt12                 TE-IS        40     rt5                  -         rt9(4)\r
+                                                                        rt11(4)\r
+10.0.255.7/32        IP TE        40     rt1                  -         rt7(4)\r
+10.0.255.9/32        IP TE        40     rt5                  -         rt9(4)\r
+10.0.255.11/32       IP TE        40     rt5                  -         rt11(4)\r
+10.0.255.10/32       IP TE        50     rt1                  -         rt10(4)\r
+10.0.255.12/32       IP TE        50     rt5                  -         rt12(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)       \r
+ -----------------------------------------------------------\r
+ 10.0.255.1/32   20      -          rt1      implicit-null  \r
+ 10.0.255.2/32   0       -          -        -              \r
+ 10.0.255.3/32   20      -          rt3      implicit-null  \r
+ 10.0.255.4/32   30      -          rt1      16040          \r
+ 10.0.255.5/32   20      -          rt5      implicit-null  \r
+ 10.0.255.6/32   30      -          rt3      16060          \r
+                         -          rt5      16060          \r
+ 10.0.255.7/32   40      -          rt1      16070          \r
+ 10.0.255.8/32   30      -          rt5      16080          \r
+ 10.0.255.9/32   40      -          rt5      16090          \r
+ 10.0.255.10/32  50      -          rt1      16100          \r
+ 10.0.255.11/32  40      -          rt5      16110          \r
+ 10.0.255.12/32  50      -          rt5      16120          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)     \r
+ ---------------------------------------------------------\r
+ 10.0.255.5/32   40      -          rt3      50600/16050  \r
+ 10.0.255.8/32   50      -          rt3      50600/16080  \r
+ 10.0.255.9/32   60      -          rt3      50600/16090  \r
+ 10.0.255.11/32  60      -          rt3      50600/16110  \r
+ 10.0.255.12/32  70      -          rt3      50600/16120  \r
+\r
+test# test isis topology 11 root rt2 remote-lfa system-id rt4\r
+P-space (self):\r
+\r
+P-space (rt1):\r
+ rt1\r
+ rt3\r
+ rt5\r
+\r
+P-space (rt3):\r
+ rt1\r
+ rt3\r
+ rt5\r
+ rt6\r
+\r
+Q-space:\r
+ rt1\r
+ rt3\r
+ rt4\r
+ rt5\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt2                                                                   \r
+10.0.255.2/32        IP internal  0                                     rt2(4)\r
+rt1                  TE-IS        50     rt1                  -         rt2(4)\r
+rt3                  TE-IS        50     rt3                  -         rt2(4)\r
+rt2                                                                   \r
+rt5                  TE-IS        60     rt3                  -         rt3(4)\r
+10.0.255.1/32        IP TE        60     rt1                  -         rt1(4)\r
+10.0.255.3/32        IP TE        60     rt3                  -         rt3(4)\r
+rt4                  TE-IS        70     rt3                  -         rt5(4)\r
+rt6                  TE-IS        70     rt3                  -         rt5(4)\r
+10.0.255.5/32        IP TE        70     rt3                  -         rt5(4)\r
+10.0.255.4/32        IP TE        80     rt3                  -         rt4(4)\r
+10.0.255.6/32        IP TE        80     rt3                  -         rt6(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt2                                                                   \r
+10.0.255.2/32        IP internal  0                                     rt2(4)\r
+rt4                  TE-IS        10     rt4                  -         rt2(4)\r
+rt5                  TE-IS        20     rt4                  -         rt4(4)\r
+rt6                  TE-IS        20     rt4                  -         rt4(4)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+rt3                  TE-IS        30     rt4                  -         rt5(4)\r
+10.0.255.5/32        IP TE        30     rt4                  -         rt5(4)\r
+10.0.255.6/32        IP TE        30     rt4                  -         rt6(4)\r
+rt2                                                                   \r
+rt1                  TE-IS        40     rt4                  -         rt2(2)\r
+10.0.255.3/32        IP TE        40     rt4                  -         rt3(4)\r
+10.0.255.1/32        IP TE        50     rt4                  -         rt1(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  50      -          rt4      16010          \r
+ 10.0.255.2/32  0       -          -        -              \r
+ 10.0.255.3/32  40      -          rt4      16030          \r
+ 10.0.255.4/32  20      -          rt4      implicit-null  \r
+ 10.0.255.5/32  30      -          rt4      16050          \r
+ 10.0.255.6/32  30      -          rt4      16060          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  50      -          rt1      implicit-null  \r
+                        -          rt3      16010          \r
+ 10.0.255.3/32  50      -          rt1      16030          \r
+                        -          rt3      implicit-null  \r
+ 10.0.255.4/32  80      -          rt3      50500/16040    \r
+ 10.0.255.5/32  60      -          rt1      16050          \r
+                        -          rt3      16050          \r
+ 10.0.255.6/32  70      -          rt3      16060          \r
+\r
+P-space (self):\r
+\r
+P-space (rt1):\r
+ rt1\r
+ rt3\r
+ rt5\r
+\r
+P-space (rt3):\r
+ rt1\r
+ rt3\r
+ rt5\r
+ rt6\r
+\r
+Q-space:\r
+ rt1\r
+ rt3\r
+ rt4\r
+ rt5\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt2                                                                   \r
+2001:db8::2/128      IP6 internal 0                                     rt2(4)\r
+rt1                  TE-IS        50     rt1                  -         rt2(4)\r
+rt3                  TE-IS        50     rt3                  -         rt2(4)\r
+rt2                                                                   \r
+rt5                  TE-IS        60     rt3                  -         rt3(4)\r
+2001:db8::1/128      IP6 internal 60     rt1                  -         rt1(4)\r
+2001:db8::3/128      IP6 internal 60     rt3                  -         rt3(4)\r
+rt4                  TE-IS        70     rt3                  -         rt5(4)\r
+rt6                  TE-IS        70     rt3                  -         rt5(4)\r
+2001:db8::5/128      IP6 internal 70     rt3                  -         rt5(4)\r
+2001:db8::4/128      IP6 internal 80     rt3                  -         rt4(4)\r
+2001:db8::6/128      IP6 internal 80     rt3                  -         rt6(4)\r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt2                                                                   \r
+2001:db8::2/128      IP6 internal 0                                     rt2(4)\r
+rt4                  TE-IS        10     rt4                  -         rt2(4)\r
+rt5                  TE-IS        20     rt4                  -         rt4(4)\r
+rt6                  TE-IS        20     rt4                  -         rt4(4)\r
+2001:db8::4/128      IP6 internal 20     rt4                  -         rt4(4)\r
+rt3                  TE-IS        30     rt4                  -         rt5(4)\r
+2001:db8::5/128      IP6 internal 30     rt4                  -         rt5(4)\r
+2001:db8::6/128      IP6 internal 30     rt4                  -         rt6(4)\r
+rt2                                                                   \r
+rt1                  TE-IS        40     rt4                  -         rt2(2)\r
+2001:db8::3/128      IP6 internal 40     rt4                  -         rt3(4)\r
+2001:db8::1/128      IP6 internal 50     rt4                  -         rt1(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  50      -          rt4      16011          \r
+ 2001:db8::2/128  0       -          -        -              \r
+ 2001:db8::3/128  40      -          rt4      16031          \r
+ 2001:db8::4/128  20      -          rt4      implicit-null  \r
+ 2001:db8::5/128  30      -          rt4      16051          \r
+ 2001:db8::6/128  30      -          rt4      16061          \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  50      -          rt1      implicit-null  \r
+                          -          rt3      16011          \r
+ 2001:db8::3/128  50      -          rt1      16031          \r
+                          -          rt3      implicit-null  \r
+ 2001:db8::4/128  80      -          rt3      50500/16041    \r
+ 2001:db8::5/128  60      -          rt1      16051          \r
+                          -          rt3      16051          \r
+ 2001:db8::6/128  70      -          rt3      16061          \r
+\r
+test# test isis topology 13 root rt1 remote-lfa system-id rt3 ipv4-only\r
+P-space (self):\r
+ rt2\r
+\r
+P-space (rt2):\r
+ rt2\r
+ rt4\r
+\r
+Q-space:\r
+ rt3\r
+ rt4\r
+ rt5\r
+ rt6\r
+ rt7\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+rt3                  TE-IS        30     rt2                  -         rt4(4)\r
+10.0.255.4/32        IP TE        30     rt2                  -         rt4(4)\r
+rt5                  TE-IS        40     rt2                  -         rt3(4)\r
+rt6                  TE-IS        40     rt2                  -         rt3(4)\r
+10.0.255.3/32        IP TE        40     rt2                  -         rt3(4)\r
+rt7                  TE-IS        50     rt2                  -         rt5(4)\r
+                                                                        rt6(4)\r
+10.0.255.5/32        IP TE        50     rt2                  -         rt5(4)\r
+10.0.255.6/32        IP TE        50     rt2                  -         rt6(4)\r
+10.0.255.7/32        IP TE        60     rt2                  -         rt7(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+                                         rt3                  -         rt3(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt7                  TE-IS        30     rt3                  -         rt5(4)\r
+                                                                        rt6(4)\r
+10.0.255.4/32        IP TE        30     rt2                  -         rt4(4)\r
+                                         rt3                  -         \r
+10.0.255.5/32        IP TE        30     rt3                  -         rt5(4)\r
+10.0.255.6/32        IP TE        30     rt3                  -         rt6(4)\r
+10.0.255.7/32        IP TE        40     rt3                  -         rt7(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+                        -          rt3      16040          \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  30      -          rt3      16060          \r
+ 10.0.255.7/32  40      -          rt3      16070          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)     \r
+ --------------------------------------------------------\r
+ 10.0.255.3/32  40      -          rt2      50400/16030  \r
+ 10.0.255.5/32  50      -          rt2      50400/16050  \r
+ 10.0.255.6/32  50      -          rt2      50400/16060  \r
+ 10.0.255.7/32  60      -          rt2      50400/16070  \r
+\r
 test# \r
 test# test isis topology 1 root rt1 ti-lfa system-id rt2\r
 P-space (self):\r
index ee89407a79d60238bba0f7d843b90ef6e84a6318..ca103948f3c906425aa87b6417fdf3ccc0b383f2 100644 (file)
  * |         +---------------------+         |
  * |         |                     |         |
  * +---------+                     +---------+
+
+ * Test topology 14:
+ * =================
+ *
+ * +---------+              +---------+
+ * |         |              |         |
+ * |   RT1   |              |   RT2   |
+ * |         +--------------+         |
+ * |         |              |         |
+ * +----+----+              +----+----+
+ *      |                        |
+ *      |                        |
+ *      |                        |
+ *      |                   +----+----+
+ *      |                   |         |
+ *      |                   |   RT3   |
+ *      +-------------------+         |
+ *      |                   |         |
+ *      |                   +----+----+
+ *      |                        |
+ *      |                        |50
+ *      |                        |
+ * +----+----+              +----+----+
+ * |         |              |         |
+ * |   RT4   |              |   RT5   |
+ * |         +--------------+         |
+ * |         |              |         |
+ * +---------+              +---------+
  */
 
 struct isis_topology test_topologies[] = {
@@ -3301,6 +3329,158 @@ struct isis_topology test_topologies[] = {
                        },
                },
        },
+       {
+               .number = 14,
+               .nodes = {
+                       {
+                               .hostname = "rt1",
+                               .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+                               .level = IS_LEVEL_1,
+                               .router_id = "10.0.255.1",
+                               .protocols = {
+                                       .ipv4 = true,
+                                       .ipv6 = true,
+                               },
+                               .networks = {
+                                       "10.0.255.1/32",
+                                       "2001:db8::1/128",
+                               },
+                               .adjacencies = {
+                                       {
+                                               .hostname = "rt1",
+                                               .pseudonode_id = 1,
+                                               .metric = 10,
+                                       },
+                                       {
+                                               .hostname = "rt2",
+                                               .metric = 10,
+                                       },
+                               },
+                       },
+                       {
+                               .hostname = "rt2",
+                               .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
+                               .level = IS_LEVEL_1,
+                               .router_id = "10.0.255.2",
+                               .protocols = {
+                                       .ipv4 = true,
+                                       .ipv6 = true,
+                               },
+                               .networks = {
+                                       "10.0.255.2/32",
+                                       "2001:db8::2/128",
+                               },
+                               .adjacencies = {
+                                       {
+                                               .hostname = "rt1",
+                                               .metric = 20,
+                                       },
+                                       {
+                                               .hostname = "rt3",
+                                               .metric = 10,
+                                       },
+                               },
+                       },
+                       {
+                               .hostname = "rt3",
+                               .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x03},
+                               .level = IS_LEVEL_1,
+                               .router_id = "10.0.255.3",
+                               .protocols = {
+                                       .ipv4 = true,
+                                       .ipv6 = true,
+                               },
+                               .networks = {
+                                       "10.0.255.3/32",
+                                       "2001:db8::3/128",
+                               },
+                               .adjacencies = {
+                                       {
+                                               .hostname = "rt1",
+                                               .pseudonode_id = 1,
+                                               .metric = 10,
+                                       },
+                                       {
+                                               .hostname = "rt2",
+                                               .metric = 10,
+                                       },
+                                       {
+                                               .hostname = "rt5",
+                                               .metric = 50,
+                                       },
+                               },
+                       },
+                       {
+                               .hostname = "rt4",
+                               .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04},
+                               .level = IS_LEVEL_1,
+                               .router_id = "10.0.255.4",
+                               .protocols = {
+                                       .ipv4 = true,
+                                       .ipv6 = true,
+                               },
+                               .networks = {
+                                       "10.0.255.4/32",
+                                       "2001:db8::4/128",
+                               },
+                               .adjacencies = {
+                                       {
+                                               .hostname = "rt1",
+                                               .pseudonode_id = 1,
+                                               .metric = 10,
+                                       },
+                                       {
+                                               .hostname = "rt5",
+                                               .metric = 10,
+                                       },
+                               },
+                       },
+                       {
+                               .hostname = "rt5",
+                               .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x05},
+                               .level = IS_LEVEL_1,
+                               .router_id = "10.0.255.5",
+                               .protocols = {
+                                       .ipv4 = true,
+                                       .ipv6 = true,
+                               },
+                               .networks = {
+                                       "10.0.255.5/32",
+                                       "2001:db8::5/128",
+                               },
+                               .adjacencies = {
+                                       {
+                                               .hostname = "rt4",
+                                               .metric = 10,
+                                       },
+                                       {
+                                               .hostname = "rt3",
+                                               .metric = 50,
+                                       },
+                               },
+                       },
+                       {
+                               .hostname = "rt1",
+                               .sysid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+                               .pseudonode_id = 1,
+                               .level = IS_LEVEL_1,
+                               .adjacencies = {
+                                       {
+                                               .hostname = "rt1",
+                                               .metric = 0,
+                                       },
+                                       {
+                                               .hostname = "rt3",
+                                               .metric = 0,
+                                       },
+                                       {
+                                               .hostname = "rt4",
+                                               .metric = 0,
+                                       },
+                               },
+                       },
+               },
+       },
        {
                /* sentinel */
        },
index 211814c1c33b4956e9bd5c50d1b86fda5940e4f4..1f173d7f1a5ff2c9d30449a2dfe4ad549881a0ce 100644 (file)
@@ -41,6 +41,16 @@ TESTS_OSPF6D =
 IGNORE_OSPF6D = --ignore=ospf6d/
 endif
 
+if ZEBRA
+TESTS_ZEBRA = \
+       tests/zebra/test_lm_plugin \
+       #end
+IGNORE_ZEBRA =
+else
+TESTS_ZEBRA =
+IGNORE_ZEBRA = --ignore=zebra/
+endif
+
 clippy_scan += \
        tests/lib/cli/test_cli.c \
        tests/ospf6d/test_lsdb.c \
@@ -81,6 +91,7 @@ check_PROGRAMS = \
        $(TESTS_BGPD) \
        $(TESTS_ISISD) \
        $(TESTS_OSPF6D) \
+       $(TESTS_ZEBRA) \
        # end
 
 if ZEROMQ
@@ -135,6 +146,7 @@ ALL_TESTS_LDADD = lib/libfrr.la $(LIBCAP)
 BGP_TEST_LDADD = bgpd/libbgp.a $(RFPLDADD) $(ALL_TESTS_LDADD) -lm
 ISISD_TEST_LDADD = isisd/libisis.a $(ALL_TESTS_LDADD)
 OSPF6_TEST_LDADD = ospf6d/libospf6.a $(ALL_TESTS_LDADD)
+ZEBRA_TEST_LDADD = zebra/label_manager.o $(ALL_TESTS_LDADD)
 
 tests_bgpd_test_aspath_CFLAGS = $(TESTS_CFLAGS)
 tests_bgpd_test_aspath_CPPFLAGS = $(TESTS_CPPFLAGS)
@@ -336,6 +348,11 @@ tests_ospf6d_test_lsdb_CPPFLAGS = $(TESTS_CPPFLAGS)
 tests_ospf6d_test_lsdb_LDADD = $(OSPF6_TEST_LDADD)
 tests_ospf6d_test_lsdb_SOURCES = tests/ospf6d/test_lsdb.c tests/lib/cli/common_cli.c
 
+tests_zebra_test_lm_plugin_CFLAGS = $(TESTS_CFLAGS)
+tests_zebra_test_lm_plugin_CPPFLAGS = $(TESTS_CPPFLAGS)
+tests_zebra_test_lm_plugin_LDADD = $(ZEBRA_TEST_LDADD)
+tests_zebra_test_lm_plugin_SOURCES = tests/zebra/test_lm_plugin.c
+
 EXTRA_DIST += \
        tests/runtests.py \
        tests/bgpd/test_aspath.py \
@@ -383,6 +400,8 @@ EXTRA_DIST += \
        tests/ospf6d/test_lsdb.py \
        tests/ospf6d/test_lsdb.in \
        tests/ospf6d/test_lsdb.refout \
+       tests/zebra/test_lm_plugin.py \
+       tests/zebra/test_lm_plugin.refout \
        # end
 
 .PHONY: tests/tests.xml
index b7c629822873ea67fec508c4f2a9f9f8ab2aa4bc..b7042d84c6a02f030d71af920e084512b39235ec 100644 (file)
@@ -48,7 +48,7 @@ RUN export DEBIAN_FRONTEND=noninteractive \
     && rm -rf /var/lib/apt/lists/*
 
 RUN export DEBIAN_FRONTEND=noninteractive \
-    && apt-key adv --keyserver keyserver.ubuntu.com --recv-key 5418F291D0D4A1AA \
+    && wget -qO- https://deb.frrouting.org/frr/keys.asc | apt-key add - \
     && echo "deb https://deb.frrouting.org/frr bionic frr-stable" > /etc/apt/sources.list.d/frr.list \
     && apt-get update \
     && apt-get install -y libyang-dev \
index d287b86175c6806f87c188717a2d6897e27c9e68..32dcb727e541ae37fe490d4df3647861d569f159 100644 (file)
@@ -13,6 +13,10 @@ router bgp 100
  neighbor fc00:0:0:8::1000 remote-as 100
  neighbor fc00:0:0:8::1000 timers 3 10
  neighbor fc00:0:0:8::2000 remote-as 200
+ neighbor 192.168.7.10 description Transit_cogent
+ neighbor 192.168.7.20 description Client_Bibi_Full
+ neighbor fc00:0:0:8::1000 description Transit_cogent_v6
+ neighbor fc00:0:0:8::2000 description Client_Toto_default
  neighbor fc00:0:0:8::2000 timers 3 10
  !
  address-family ipv4 unicast
diff --git a/tests/topotests/all-protocol-startup/r1/ip_nht.ref b/tests/topotests/all-protocol-startup/r1/ip_nht.ref
new file mode 100644 (file)
index 0000000..098e3bf
--- /dev/null
@@ -0,0 +1,60 @@
+1.1.1.1
+ resolved via static
+ is directly connected, r1-eth1
+ Client list: pbr(fd XX)
+1.1.1.2
+ resolved via static
+ is directly connected, r1-eth2
+ Client list: pbr(fd XX)
+1.1.1.3
+ resolved via static
+ is directly connected, r1-eth3
+ Client list: pbr(fd XX)
+1.1.1.4
+ resolved via static
+ is directly connected, r1-eth4
+ Client list: pbr(fd XX)
+1.1.1.5
+ resolved via static
+ is directly connected, r1-eth5
+ Client list: pbr(fd XX)
+1.1.1.6
+ resolved via static
+ is directly connected, r1-eth6
+ Client list: pbr(fd XX)
+1.1.1.7
+ resolved via static
+ is directly connected, r1-eth7
+ Client list: pbr(fd XX)
+1.1.1.8
+ resolved via static
+ is directly connected, r1-eth8
+ Client list: pbr(fd XX)
+2.2.2.1
+ unresolved
+ Client list: pbr(fd XX)
+4.4.4.1
+ unresolved
+ Client list: pbr(fd XX)
+4.4.4.2
+ unresolved
+ Client list: pbr(fd XX)
+192.168.0.2
+ resolved via connected
+ is directly connected, r1-eth0
+ Client list: static(fd XX)
+192.168.0.4
+ resolved via connected
+ is directly connected, r1-eth0
+ Client list: static(fd XX)
+192.168.7.10
+ resolved via connected
+ is directly connected, r1-eth7
+ Client list: bgp(fd XX)
+192.168.7.20(Connected)
+ resolved via connected
+ is directly connected, r1-eth7
+ Client list: bgp(fd XX)
+192.168.161.4
+ unresolved
+ Client list: pbr(fd XX)
diff --git a/tests/topotests/all-protocol-startup/r1/ipv6_nht.ref b/tests/topotests/all-protocol-startup/r1/ipv6_nht.ref
new file mode 100644 (file)
index 0000000..0255ecd
--- /dev/null
@@ -0,0 +1,13 @@
+fc00::2
+ resolved via connected
+ is directly connected, r1-eth0
+ Client list: static(fd XX)
+fc00:0:0:8::1000
+ resolved via connected
+ is directly connected, r1-eth8
+ Client list: bgp(fd XX)
+fc00:0:0:8::2000(Connected)
+ resolved via connected
+ is directly connected, r1-eth8
+ Client list: bgp(fd XX)
\ No newline at end of file
index 1e41263e78ae49001ced3575c34fe7278f0b460f..02466872000a485cd2567864361afc1230900952 100644 (file)
@@ -3,6 +3,6 @@ BGP table version 1
 RIB entries 1, using XXXX bytes of memory
 Peers 2, using XXXX KiB of memory
 
-Neighbor         V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt
-fc00:0:0:8::1000 4        100         0         0        0    0    0    never       Active        0
-fc00:0:0:8::2000 4        200         0         0        0    0    0    never       Active        0
+Neighbor         V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt Desc
+fc00:0:0:8::1000 4        100         0         0        0    0    0    never       Active        0 Transit_cogent_v6
+fc00:0:0:8::2000 4        200         0         0        0    0    0    never       Active        0 Client_Toto_default
index 3ffbf3ff422844b786f7e1328eea196c5ddc9b3a..deeae87fa3b7f270ae462f562c9a85ef56c59062 100644 (file)
@@ -3,8 +3,8 @@ BGP table version 1
 RIB entries 1, using XXXX bytes of memory
 Peers 4, using XXXX KiB of memory
 
-Neighbor         V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt
-192.168.7.10     4        100         0         0        0    0    0    never       Active        0
-192.168.7.20     4        200         0         0        0    0    0    never       Active        0
-fc00:0:0:8::1000 4        100         0         0        0    0    0    never       Active        0
-fc00:0:0:8::2000 4        200         0         0        0    0    0    never       Active        0
+Neighbor         V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt Desc
+192.168.7.10     4        100         0         0        0    0    0    never       Active        0 Transit_cogent
+192.168.7.20     4        200         0         0        0    0    0    never       Active        0 Client_Bibi_Full
+fc00:0:0:8::1000 4        100         0         0        0    0    0    never       Active        0 Transit_cogent_v6
+fc00:0:0:8::2000 4        200         0         0        0    0    0    never       Active        0 Client_Toto_default
index 0254ff6af6a404aeb5db17b5cc39702455669c53..24bef07ec25e12eb78d8d52fd53eb254da86e846 100644 (file)
@@ -82,7 +82,9 @@ class NetworkTopo(Topo):
 ##
 #####################################################
 
-
+@pytest.mark.isis
+@pytest.mark.ospf
+@pytest.mark.rip
 def setup_module(module):
     global topo, net
     global fatal_error
@@ -269,6 +271,9 @@ def test_error_messages_daemons():
                 error_logs += log
 
         log = net["r1"].getStdErr("nhrpd")
+        # NHRPD shows YANG model not embedded messages
+        # Ignore these
+        log = re.sub(r".*YANG model.*not embedded.*", "", log).rstrip()
         if log:
             error_logs += "r%s NHRPd StdErr Output:\n" % i
             error_logs += log
@@ -285,7 +290,7 @@ def test_error_messages_daemons():
 
         log = net["r%s" % i].getStdErr("zebra")
         if log:
-            error_logs += "r%s Zebra StdErr Output:\n"
+            error_logs += "r%s Zebra StdErr Output:\n" % i
             error_logs += log
 
     if error_logs:
@@ -1014,6 +1019,53 @@ def test_bgp_ipv6_summary():
     # CLI(net)
 
 
+def test_nht():
+    print("\n\n**** Test that nexthop tracking is at least nominally working ****\n")
+
+    thisDir = os.path.dirname(os.path.realpath(__file__))
+
+    for i in range(1, 2):
+        nhtFile = "%s/r%s/ip_nht.ref" % (thisDir, i)
+        expected = open(nhtFile).read().rstrip()
+        expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+        actual = net["r%s" % i].cmd('vtysh -c "show ip nht" 2> /dev/null').rstrip()
+        actual = re.sub(r"fd [0-9][0-9]", "fd XX", actual)
+        actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+
+        diff = topotest.get_textdiff(
+            actual,
+            expected,
+            title1="Actual `show ip nht`",
+            title2="Expected `show ip nht`",
+        )
+
+        if diff:
+            assert 0, "r%s failed ip nht check:\n%s\n" % (i, diff)
+        else:
+            print("show ip nht is ok\n")
+
+        nhtFile = "%s/r%s/ipv6_nht.ref" % (thisDir, i)
+        expected = open(nhtFile).read().rstrip()
+        expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+        actual = net["r%s" % i].cmd('vtysh -c "show ipv6 nht" 2> /dev/null').rstrip()
+        actual = re.sub(r"fd [0-9][0-9]", "fd XX", actual)
+        actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+
+        diff = topotest.get_textdiff(
+            actual,
+            expected,
+            title1="Actual `show ip nht`",
+            title2="Expected `show ip nht`",
+        )
+
+        if diff:
+            assert 0, "r%s failed ipv6 nht check:\n%s\n" % (i, diff)
+        else:
+            print("show ipv6 nht is ok\n")
+
+
 def test_bgp_ipv4():
     global fatal_error
     global net
@@ -1065,7 +1117,7 @@ def test_bgp_ipv4():
 
         if not success:
             resultstr = "No template matched.\n"
-            for f in diffresult.iterkeys():
+            for f in diffresult.keys():
                 resultstr += "template %s: r%s failed SHOW BGP IPv4 check:\n%s\n" % (
                     f,
                     i,
@@ -1134,7 +1186,7 @@ def test_bgp_ipv6():
 
         if not success:
             resultstr = "No template matched.\n"
-            for f in diffresult.iterkeys():
+            for f in diffresult.keys():
                 resultstr += "template %s: r%s failed SHOW BGP IPv6 check:\n%s\n" % (
                     f,
                     i,
index 595132214bfdf8dac7a5e9d667269a5e720f58a5..cc1c1e3a0cd6dd853984efd54219880bdbd2ff00 100644 (file)
@@ -64,7 +64,7 @@ class BFDTopo(Topo):
         switch.add_link(tgen.gears["r2"])
         switch.add_link(tgen.gears["r3"])
 
-
+@pytest.mark.bfd
 def setup_module(mod):
     "Sets up the pytest environment"
     tgen = Topogen(BFDTopo, mod.__name__)
@@ -74,7 +74,8 @@ def setup_module(mod):
 
     for rname, router in router_list.items():
         router.load_config(
-            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)),
+            TopoRouter.RD_ZEBRA,
+            os.path.join(CWD, "{}/zebra.conf".format(rname)),
         )
         router.load_config(
             TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname))
index 1adfec76d84d4ee08c66b30e8d5686cb89c12db7..23da7ed850766dbae7fef0af4940bf3f3aa076f6 100644 (file)
@@ -127,7 +127,8 @@ class TemplateTopo(Topo):
         switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5")
         switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4")
 
-
+@pytest.mark.bfd
+@pytest.mark.isis
 def setup_module(mod):
     "Sets up the pytest environment"
     tgen = Topogen(TemplateTopo, mod.__name__)
diff --git a/tests/topotests/bfd-ospf-topo1/__init__.py b/tests/topotests/bfd-ospf-topo1/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt1/bfdd.conf
new file mode 100644 (file)
index 0000000..610a20f
--- /dev/null
@@ -0,0 +1,9 @@
+log file bfdd.log
+log timestamp precision 3
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
+bfd
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt1/ospf6d.conf
new file mode 100644 (file)
index 0000000..18def59
--- /dev/null
@@ -0,0 +1,21 @@
+log file ospf6d.log
+log timestamp precision 3
+!
+hostname rt1
+!
+password 1
+!
+interface eth-rt2
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 bfd
+!
+interface eth-rt3
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 bfd
+!
+router ospf6
+ ospf6 router-id 1.1.1.1
+ interface eth-rt2 area 0.0.0.0
+ interface eth-rt3 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt1/ospfd.conf
new file mode 100644 (file)
index 0000000..07b42f9
--- /dev/null
@@ -0,0 +1,26 @@
+log file ospfd.log
+log timestamp precision 3
+!
+hostname rt1
+!
+password 1
+!
+debug ospf event
+debug ospf zebra
+!
+interface lo
+ ip ospf area 0.0.0.0
+!
+interface eth-rt2
+ ip ospf area 0.0.0.0
+ ip ospf bfd
+!
+interface eth-rt3
+ ip ospf area 0.0.0.0
+ ip ospf bfd
+!
+router ospf
+ ospf router-id 1.1.1.1
+ passive interface lo
+ router-info area 0.0.0.0
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ip_route.ref b/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ip_route.ref
new file mode 100644 (file)
index 0000000..f354eff
--- /dev/null
@@ -0,0 +1,74 @@
+{
+  "2.2.2.2\/32":[
+    {
+      "prefix":"2.2.2.2\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.1.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "3.3.3.3\/32":[
+    {
+      "prefix":"3.3.3.3\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.2.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "4.4.4.4\/32":[
+    {
+      "prefix":"4.4.4.4\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.2.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "5.5.5.5\/32":[
+    {
+      "prefix":"5.5.5.5\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.1.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ipv6_route.ref b/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ipv6_route.ref
new file mode 100644 (file)
index 0000000..6465efb
--- /dev/null
@@ -0,0 +1,70 @@
+{
+  "::ffff:202:202\/128":[
+    {
+      "prefix":"::ffff:202:202\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "::ffff:303:303\/128":[
+    {
+      "prefix":"::ffff:303:303\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "::ffff:404:404\/128":[
+    {
+      "prefix":"::ffff:404:404\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "::ffff:505:505\/128":[
+    {
+      "prefix":"::ffff:505:505\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step2/show_bfd_peers.ref b/tests/topotests/bfd-ospf-topo1/rt1/step2/show_bfd_peers.ref
new file mode 100644 (file)
index 0000000..63f0d50
--- /dev/null
@@ -0,0 +1,26 @@
+[
+  {
+    "interface": "eth-rt3",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  },
+  {
+    "interface": "eth-rt2",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  },
+  {
+    "interface": "eth-rt3",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  },
+  {
+    "interface": "eth-rt2",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  }
+]
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_healthy.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_healthy.ref
new file mode 100644 (file)
index 0000000..42051f9
--- /dev/null
@@ -0,0 +1,28 @@
+[
+  {
+    "peer": "10.0.2.2",
+    "interface": "eth-rt3",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  },
+  {
+    "peer": "10.0.1.2",
+    "interface": "eth-rt2",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  },
+  {
+    "interface": "eth-rt3",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  },
+  {
+    "interface": "eth-rt2",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  }
+]
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt2_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt2_down.ref
new file mode 100644 (file)
index 0000000..d844ee6
--- /dev/null
@@ -0,0 +1,15 @@
+[
+  {
+    "peer": "10.0.2.2",
+    "interface": "eth-rt3",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  },
+  {
+    "interface": "eth-rt3",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  }
+]
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt3_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt3_down.ref
new file mode 100644 (file)
index 0000000..3279908
--- /dev/null
@@ -0,0 +1,15 @@
+[
+  {
+    "peer": "10.0.1.2",
+    "interface": "eth-rt2",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  },
+  {
+    "interface": "eth-rt2",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  }
+]
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_healthy.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_healthy.ref
new file mode 100644 (file)
index 0000000..f354eff
--- /dev/null
@@ -0,0 +1,74 @@
+{
+  "2.2.2.2\/32":[
+    {
+      "prefix":"2.2.2.2\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.1.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "3.3.3.3\/32":[
+    {
+      "prefix":"3.3.3.3\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.2.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "4.4.4.4\/32":[
+    {
+      "prefix":"4.4.4.4\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.2.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "5.5.5.5\/32":[
+    {
+      "prefix":"5.5.5.5\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.1.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt2_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt2_down.ref
new file mode 100644 (file)
index 0000000..43eecd0
--- /dev/null
@@ -0,0 +1,74 @@
+{
+  "2.2.2.2\/32":[
+    {
+      "prefix":"2.2.2.2\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.2.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "3.3.3.3\/32":[
+    {
+      "prefix":"3.3.3.3\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.2.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "4.4.4.4\/32":[
+    {
+      "prefix":"4.4.4.4\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.2.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "5.5.5.5\/32":[
+    {
+      "prefix":"5.5.5.5\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.2.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt3_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt3_down.ref
new file mode 100644 (file)
index 0000000..409af63
--- /dev/null
@@ -0,0 +1,74 @@
+{
+  "2.2.2.2\/32":[
+    {
+      "prefix":"2.2.2.2\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.1.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "3.3.3.3\/32":[
+    {
+      "prefix":"3.3.3.3\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.1.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "4.4.4.4\/32":[
+    {
+      "prefix":"4.4.4.4\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.1.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "5.5.5.5\/32":[
+    {
+      "prefix":"5.5.5.5\/32",
+      "protocol":"ospf",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.1.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_healthy.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_healthy.ref
new file mode 100644 (file)
index 0000000..6465efb
--- /dev/null
@@ -0,0 +1,70 @@
+{
+  "::ffff:202:202\/128":[
+    {
+      "prefix":"::ffff:202:202\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "::ffff:303:303\/128":[
+    {
+      "prefix":"::ffff:303:303\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "::ffff:404:404\/128":[
+    {
+      "prefix":"::ffff:404:404\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "::ffff:505:505\/128":[
+    {
+      "prefix":"::ffff:505:505\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt2_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt2_down.ref
new file mode 100644 (file)
index 0000000..cfb1ef1
--- /dev/null
@@ -0,0 +1,70 @@
+{
+  "::ffff:202:202\/128":[
+    {
+      "prefix":"::ffff:202:202\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "::ffff:303:303\/128":[
+    {
+      "prefix":"::ffff:303:303\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "::ffff:404:404\/128":[
+    {
+      "prefix":"::ffff:404:404\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "::ffff:505:505\/128":[
+    {
+      "prefix":"::ffff:505:505\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt3_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt3_down.ref
new file mode 100644 (file)
index 0000000..58b44da
--- /dev/null
@@ -0,0 +1,70 @@
+{
+  "::ffff:202:202\/128":[
+    {
+      "prefix":"::ffff:202:202\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "::ffff:303:303\/128":[
+    {
+      "prefix":"::ffff:303:303\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "::ffff:404:404\/128":[
+    {
+      "prefix":"::ffff:404:404\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "::ffff:505:505\/128":[
+    {
+      "prefix":"::ffff:505:505\/128",
+      "protocol":"ospf6",
+      "selected":true,
+      "destSelected":true,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt1/zebra.conf
new file mode 100644 (file)
index 0000000..6003125
--- /dev/null
@@ -0,0 +1,25 @@
+log file zebra.log
+log timestamp precision 3
+!
+hostname rt1
+!
+debug zebra kernel
+debug zebra packet
+debug zebra events
+debug zebra rib
+!
+interface lo
+ ip address 1.1.1.1/32
+ ipv6 address ::ffff:0101:0101/128
+!
+interface eth-rt2
+ ip address 10.0.1.1/24
+!
+interface eth-rt3
+ ip address 10.0.2.1/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt2/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt2/bfdd.conf
new file mode 100644 (file)
index 0000000..437f063
--- /dev/null
@@ -0,0 +1,7 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
+bfd
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt2/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt2/ospf6d.conf
new file mode 100644 (file)
index 0000000..2f35099
--- /dev/null
@@ -0,0 +1,19 @@
+log file ospf6d.log
+!
+hostname rt2
+!
+password 1
+!
+interface eth-rt1
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 bfd
+!
+interface eth-rt5
+ ipv6 ospf6 network broadcast
+!
+router ospf6
+ ospf6 router-id 2.2.2.2
+ interface eth-rt1 area 0.0.0.0
+ interface eth-rt5 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt2/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt2/ospfd.conf
new file mode 100644 (file)
index 0000000..a05d8b5
--- /dev/null
@@ -0,0 +1,24 @@
+log file ospfd.log
+!
+hostname rt2
+!
+password 1
+!
+debug ospf event
+debug ospf zebra
+!
+interface lo
+ ip ospf area 0.0.0.0
+!
+interface eth-rt1
+ ip ospf area 0.0.0.0
+ ip ospf bfd
+!
+interface eth-rt5
+ ip ospf area 0.0.0.0
+!
+router ospf
+ ospf router-id 2.2.2.2
+ passive interface lo
+ router-info area 0.0.0.0
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt2/step2/show_bfd_peers.ref b/tests/topotests/bfd-ospf-topo1/rt2/step2/show_bfd_peers.ref
new file mode 100644 (file)
index 0000000..d6df1eb
--- /dev/null
@@ -0,0 +1,14 @@
+[
+  {
+    "interface": "eth-rt1",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  },
+  {
+    "interface": "eth-rt1",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  }
+]
diff --git a/tests/topotests/bfd-ospf-topo1/rt2/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt2/zebra.conf
new file mode 100644 (file)
index 0000000..5fc7fc5
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt2
+!
+debug zebra kernel
+debug zebra packet
+!
+interface lo
+ ip address 2.2.2.2/32
+ ipv6 address ::ffff:0202:0202/128
+!
+interface eth-rt1
+ ip address 10.0.1.2/24
+!
+interface eth-rt5
+ ip address 10.0.3.1/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt3/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt3/bfdd.conf
new file mode 100644 (file)
index 0000000..437f063
--- /dev/null
@@ -0,0 +1,7 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
+bfd
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt3/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt3/ospf6d.conf
new file mode 100644 (file)
index 0000000..3e87770
--- /dev/null
@@ -0,0 +1,19 @@
+log file ospf6d.log
+!
+hostname rt3
+!
+password 1
+!
+interface eth-rt1
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 bfd
+!
+interface eth-rt4
+ ipv6 ospf6 network broadcast
+!
+router ospf6
+ ospf6 router-id 3.3.3.3
+ interface eth-rt1 area 0.0.0.0
+ interface eth-rt4 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt3/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt3/ospfd.conf
new file mode 100644 (file)
index 0000000..1196e6d
--- /dev/null
@@ -0,0 +1,24 @@
+log file ospfd.log
+!
+hostname rt3
+!
+password 1
+!
+debug ospf event
+debug ospf zebra
+!
+interface lo
+ ip ospf area 0.0.0.0
+!
+interface eth-rt1
+ ip ospf area 0.0.0.0
+ ip ospf bfd
+!
+interface eth-rt4
+ ip ospf area 0.0.0.0
+!
+router ospf
+ ospf router-id 3.3.3.3
+ passive interface lo
+ router-info area 0.0.0.0
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt3/step2/show_bfd_peers.ref b/tests/topotests/bfd-ospf-topo1/rt3/step2/show_bfd_peers.ref
new file mode 100644 (file)
index 0000000..d6df1eb
--- /dev/null
@@ -0,0 +1,14 @@
+[
+  {
+    "interface": "eth-rt1",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  },
+  {
+    "interface": "eth-rt1",
+    "status": "up",
+    "diagnostic": "ok",
+    "remote-diagnostic": "ok"
+  }
+]
diff --git a/tests/topotests/bfd-ospf-topo1/rt3/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt3/zebra.conf
new file mode 100644 (file)
index 0000000..d368de9
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt3
+!
+debug zebra kernel
+debug zebra packet
+!
+interface lo
+ ip address 3.3.3.3/32
+ ipv6 address ::ffff:0303:0303/128
+!
+interface eth-rt1
+ ip address 10.0.2.2/24
+!
+interface eth-rt4
+ ip address 10.0.4.1/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt4/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt4/bfdd.conf
new file mode 100644 (file)
index 0000000..f35e772
--- /dev/null
@@ -0,0 +1,5 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt4/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt4/ospf6d.conf
new file mode 100644 (file)
index 0000000..bccd1e7
--- /dev/null
@@ -0,0 +1,18 @@
+log file ospf6d.log
+!
+hostname rt4
+!
+password 1
+!
+interface eth-rt3
+ ipv6 ospf6 network broadcast
+!
+interface eth-rt5
+ ipv6 ospf6 network broadcast
+!
+router ospf6
+ ospf6 router-id 4.4.4.4
+ interface eth-rt3 area 0.0.0.0
+ interface eth-rt5 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt4/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt4/ospfd.conf
new file mode 100644 (file)
index 0000000..3a2568b
--- /dev/null
@@ -0,0 +1,23 @@
+log file ospfd.log
+!
+hostname rt4
+!
+password 1
+!
+debug ospf event
+debug ospf zebra
+!
+interface lo
+ ip ospf area 0.0.0.0
+!
+interface eth-rt3
+ ip ospf area 0.0.0.0
+!
+interface eth-rt5
+ ip ospf area 0.0.0.0
+!
+router ospf
+ ospf router-id 4.4.4.4
+ passive interface lo
+ router-info area 0.0.0.0
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt4/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt4/zebra.conf
new file mode 100644 (file)
index 0000000..7b053ba
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt4
+!
+debug zebra kernel
+debug zebra packet
+!
+interface lo
+ ip address 4.4.4.4/32
+ ipv6 address ::ffff:0404:0404/128
+!
+interface eth-rt3
+ ip address 10.0.4.2/24
+!
+interface eth-rt5
+ ip address 10.0.5.1/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt5/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt5/bfdd.conf
new file mode 100644 (file)
index 0000000..f35e772
--- /dev/null
@@ -0,0 +1,5 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt5/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt5/ospf6d.conf
new file mode 100644 (file)
index 0000000..7668622
--- /dev/null
@@ -0,0 +1,18 @@
+log file ospf6d.log
+!
+hostname rt5
+!
+password 1
+!
+interface eth-rt2
+ ipv6 ospf6 network broadcast
+!
+interface eth-rt4
+ ipv6 ospf6 network broadcast
+!
+router ospf6
+ ospf6 router-id 5.5.5.5
+ interface eth-rt2 area 0.0.0.0
+ interface eth-rt4 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt5/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt5/ospfd.conf
new file mode 100644 (file)
index 0000000..a35de5f
--- /dev/null
@@ -0,0 +1,23 @@
+log file ospfd.log
+!
+hostname rt5
+!
+password 1
+!
+debug ospf event
+debug ospf zebra
+!
+interface lo
+ ip ospf area 0.0.0.0
+!
+interface eth-rt2
+ ip ospf area 0.0.0.0
+!
+interface eth-rt4
+ ip ospf area 0.0.0.0
+!
+router ospf
+ ospf router-id 5.5.5.5
+ passive interface lo
+ router-info area 0.0.0.0
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt5/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt5/zebra.conf
new file mode 100644 (file)
index 0000000..0b7c9e0
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt5
+!
+debug zebra kernel
+debug zebra packet
+!
+interface lo
+ ip address 5.5.5.5/32
+ ipv6 address ::ffff:0505:0505/128
+!
+interface eth-rt2
+ ip address 10.0.3.2/24
+!
+interface eth-rt4
+ ip address 10.0.5.2/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py b/tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py
new file mode 100755 (executable)
index 0000000..1cec627
--- /dev/null
@@ -0,0 +1,307 @@
+#!/usr/bin/env python
+
+#
+# test_bfd_ospf_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bfd_ospf_topo1.py:
+
+                        +---------+
+                        |         |
+           eth-rt2 (.1) |   RT1   | eth-rt3 (.1)
+             +----------+ 1.1.1.1 +----------+
+             |          |         |          |
+             |          +---------+          |
+             |                               |
+             |                   10.0.2.0/24 |
+             |                               |
+             |                       eth-rt1 | (.2)
+             | 10.0.1.0/24              +----+----+
+             |                          |         |
+             |                          |   RT3   |
+             |                          | 3.3.3.3 |
+             |                          |         |
+        (.2) | eth-rt1                  +----+----+
+        +----+----+                  eth-rt4 | (.1)
+        |         |                          |
+        |   RT2   |                          |
+        | 2.2.2.2 |              10.0.4.0/24 |
+        |         |                          |
+        +----+----+                          |
+        (.1) | eth-rt5               eth-rt3 | (.2)
+             |                          +----+----+
+             |                          |         |
+             |                          |   RT4   |
+             |                          | 4.4.4.4 |
+             |                          |         |
+             |                          +----+----+
+             | 10.0.3.0/24           eth-rt5 | (.1)
+             |                               |
+             |                               |
+             |                   10.0.5.0/24 |
+             |                               |
+             |          +---------+          |
+             |          |         |          |
+             +----------+   RT5   +----------+
+           eth-rt2 (.2) | 5.5.5.5 | eth-rt4 (.2)
+                        |         |
+                        +---------+
+
+"""
+
+import os
+import sys
+import pytest
+import json
+import re
+from time import sleep
+from time import time
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+
+class TemplateTopo(Topo):
+    "Test topology builder"
+
+    def build(self, *_args, **_opts):
+        "Build function"
+        tgen = get_topogen(self)
+
+        #
+        # Define FRR Routers
+        #
+        for router in ["rt1", "rt2", "rt3", "rt4", "rt5"]:
+            tgen.add_router(router)
+
+        #
+        # Define connections
+        #
+        switch = tgen.add_switch("s1")
+        switch.add_link(tgen.gears["rt1"], nodeif="eth-rt2")
+        switch.add_link(tgen.gears["rt2"], nodeif="eth-rt1")
+
+        switch = tgen.add_switch("s2")
+        switch.add_link(tgen.gears["rt1"], nodeif="eth-rt3")
+        switch.add_link(tgen.gears["rt3"], nodeif="eth-rt1")
+
+        switch = tgen.add_switch("s3")
+        switch.add_link(tgen.gears["rt2"], nodeif="eth-rt5")
+        switch.add_link(tgen.gears["rt5"], nodeif="eth-rt2")
+
+        switch = tgen.add_switch("s4")
+        switch.add_link(tgen.gears["rt3"], nodeif="eth-rt4")
+        switch.add_link(tgen.gears["rt4"], nodeif="eth-rt3")
+
+        switch = tgen.add_switch("s5")
+        switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5")
+        switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4")
+
+
+def setup_module(mod):
+    "Sets up the pytest environment"
+    tgen = Topogen(TemplateTopo, mod.__name__)
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+
+    # For all registered routers, load the zebra configuration file
+    for rname, router in router_list.iteritems():
+        router.load_config(
+            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_OSPF6, os.path.join(CWD, "{}/ospf6d.conf".format(rname))
+        )
+
+    tgen.start_router()
+
+
+def teardown_module(mod):
+    "Teardown the pytest environment"
+    tgen = get_topogen()
+
+    # This function tears down the whole topology.
+    tgen.stop_topology()
+
+
+def print_cmd_result(rname, command):
+    print(get_topogen().gears[rname].vtysh_cmd(command, isjson=False))
+
+
+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)
+
+    tgen = get_topogen()
+    filename = "{}/{}/{}".format(CWD, rname, reference)
+    expected = json.loads(open(filename).read())
+
+    # Run test function until we get an result. Wait at most 60 seconds.
+    test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
+    _, diff = topotest.run_and_expect(test_func, None, count=count, wait=wait)
+    assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
+    assert diff is None, assertmsg
+
+
+## TEST STEPS
+
+
+def test_rib_ospf_step1():
+    logger.info("Test (step 1): verify RIB for OSPF")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    router_compare_json_output(
+        "rt1", "show ip route ospf json", "step1/show_ip_route.ref"
+    )
+    router_compare_json_output(
+        "rt1", "show ipv6 route ospf json", "step1/show_ipv6_route.ref"
+    )
+
+
+def test_bfd_ospf_sessions_step2():
+    logger.info("Test (step 2): verify BFD peers for OSPF")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # BFD is just used on three routers
+    for rt in ["rt1", "rt2", "rt3"]:
+        router_compare_json_output(
+            rt, "show bfd peers json", "step2/show_bfd_peers.ref"
+        )
+
+
+def test_bfd_ospf_interface_failure_rt2_step3():
+    logger.info("Test (step 3): Check failover handling with RT2 down")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # Let's kill the interface on rt2 and see what happens with the RIB and BFD on rt1
+    tgen.gears["rt2"].link_enable("eth-rt1", enabled=False)
+
+    # By default BFD provides a recovery time of 900ms plus jitter, so let's wait
+    # initial 2 seconds to let the CI not suffer.
+    # TODO: add check for array size
+    sleep(2)
+    router_compare_json_output(
+        "rt1", "show ip route ospf json", "step3/show_ip_route_rt2_down.ref", 1, 0
+    )
+    router_compare_json_output(
+        "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_rt2_down.ref", 1, 0
+    )
+    router_compare_json_output(
+        "rt1", "show bfd peers json", "step3/show_bfd_peers_rt2_down.ref", 1, 0
+    )
+
+    # Check recovery, this can take some time
+    tgen.gears["rt2"].link_enable("eth-rt1", enabled=True)
+
+    router_compare_json_output(
+        "rt1", "show ip route ospf json", "step3/show_ip_route_healthy.ref"
+    )
+    router_compare_json_output(
+        "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_healthy.ref"
+    )
+    router_compare_json_output(
+        "rt1", "show bfd peers json", "step3/show_bfd_peers_healthy.ref"
+    )
+
+
+def test_bfd_ospf_interface_failure_rt3_step3():
+    logger.info("Test (step 3): Check failover handling with RT3 down")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # Let's kill the interface on rt3 and see what happens with the RIB and BFD on rt1
+    tgen.gears["rt3"].link_enable("eth-rt1", enabled=False)
+
+    # By default BFD provides a recovery time of 900ms plus jitter, so let's wait
+    # initial 2 seconds to let the CI not suffer.
+    # TODO: add check for array size
+    sleep(2)
+    router_compare_json_output(
+        "rt1", "show ip route ospf json", "step3/show_ip_route_rt3_down.ref", 1, 0
+    )
+    router_compare_json_output(
+        "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_rt3_down.ref", 1, 0
+    )
+    router_compare_json_output(
+        "rt1", "show bfd peers json", "step3/show_bfd_peers_rt3_down.ref", 1, 0
+    )
+
+    # Check recovery, this can take some time
+    tgen.gears["rt3"].link_enable("eth-rt1", enabled=True)
+
+    router_compare_json_output(
+        "rt1", "show ip route ospf json", "step3/show_ip_route_healthy.ref"
+    )
+    router_compare_json_output(
+        "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_healthy.ref"
+    )
+    router_compare_json_output(
+        "rt1", "show bfd peers json", "step3/show_bfd_peers_healthy.ref"
+    )
+
+
+def test_memory_leak():
+    "Run the memory leak test and report results."
+    tgen = get_topogen()
+    if not tgen.is_memleak_enabled():
+        pytest.skip("Memory leak test/report is disabled")
+
+    tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index bd3b876eeb117c9fbc9f9a0135ea2ca7be48da1c..6283f03ddf0d4cc05a46508cf9b217a63e966dca 100644 (file)
@@ -77,7 +77,8 @@ class BFDProfTopo(Topo):
         switch.add_link(tgen.gears["r1"])
         switch.add_link(tgen.gears["r6"])
 
-
+@pytest.mark.bfd
+@pytest.mark.isis
 def setup_module(mod):
     "Sets up the pytest environment"
     tgen = Topogen(BFDProfTopo, mod.__name__)
index 6e589d55eb0bea193a62b450c6aa4c6156a2daba..4c13fdcfc5fa7d1eb82bed344765f4104542ee55 100644 (file)
@@ -69,7 +69,7 @@ class BFDTopo(Topo):
         switch.add_link(tgen.gears["r2"])
         switch.add_link(tgen.gears["r4"])
 
-
+@pytest.mark.bfd
 def setup_module(mod):
     "Sets up the pytest environment"
     tgen = Topogen(BFDTopo, mod.__name__)
index feb4576bd305a888c00baa04fd6ab31520bf322f..5181a40f477754ceb196b67530bac857316808dd 100644 (file)
@@ -70,7 +70,7 @@ class BFDTopo(Topo):
         switch.add_link(tgen.gears["r2"])
         switch.add_link(tgen.gears["r4"])
 
-
+@pytest.mark.bfd
 def setup_module(mod):
     "Sets up the pytest environment"
     tgen = Topogen(BFDTopo, mod.__name__)
index 5fed135f8d3bfb7da38fd36ddbc7749d1a562ffa..956b52658309f61501339ba77657b1818305fb75 100644 (file)
@@ -70,7 +70,7 @@ class BFDTopo(Topo):
         switch.add_link(tgen.gears["r2"])
         switch.add_link(tgen.gears["r4"])
 
-
+@pytest.mark.bfd
 def setup_module(mod):
     "Sets up the pytest environment"
     tgen = Topogen(BFDTopo, mod.__name__)
index aab35073cf275ebc6ac85c2564dec3ea3bdf3a84..dde3c090b565756584afef7474d4a650c172fa62 100644 (file)
@@ -1,4 +1,3 @@
-log file /tmp/topotests/test_bgp_auth/R1/bgpd.log debugging
 debug bgp neighbor-events
 
 router bgp 65001 vrf blue
index 73aa8c1a0327416c269446a4670d499a5ea9b6a0..781f906d3a6e28520f33eb7e45fe989d74963cce 100644 (file)
@@ -1,4 +1,3 @@
-log file /tmp/topotests/test_bgp_auth/R1/bgpd.log debugging
 debug bgp neighbor-events
 
 router bgp 65001 vrf blue
index d39915335ae46e4699c1b0c37cf7f46f90569387..a0b062c44c070d7f64c1e6f9fe0eee9a38f3547e 100644 (file)
@@ -1,4 +1,3 @@
-log file zebra.log
 !
 interface lo
  ip address 1.1.1.1/32
@@ -18,4 +17,4 @@ interface R1-eth4 vrf red
  ip address 10.10.0.1/24
 interface R1-eth5 vrf red
  ip address 10.20.0.1/24
-!
\ No newline at end of file
+!
index fece68472a688fe7b64b2141751fc886237313e6..fed4c27c1625e3b46988a178070915706c8500bd 100644 (file)
@@ -1,4 +1,3 @@
-log file zebra.log
 !
 interface lo
  ip address 2.2.2.2/32
@@ -18,4 +17,4 @@ interface R2-eth4 vrf red
  ip address 10.10.0.2/24
 interface R2-eth5 vrf red
  ip address 10.30.0.2/24
-!
\ No newline at end of file
+!
index 0fe3acdfd0ab37cbee039b96e4aa068785b7cf12..d49c98b1689f5eebd1015473bace1f0bfb74e8d7 100644 (file)
@@ -1,4 +1,3 @@
-log file zebra.log
 !
 interface lo
  ip address 3.3.3.3/32
@@ -18,4 +17,4 @@ interface R3-eth4 vrf red
  ip address 10.20.0.3/24
 interface R3-eth5 vrf red
  ip address 10.30.0.3/24
-!
\ No newline at end of file
+!
index b3b7256ac44dc476429971f3f6a7a84ed85dc9b3..b701a0d61e6f557c2b9f4047070b748ca0ddc68f 100644 (file)
@@ -282,10 +282,26 @@ def test_BGP_config_with_invalid_ASN_p2(request):
 
     # Api call to modify AS number
     input_dict = {
-        "r1": {"bgp": {"local_as": 0,}},
-        "r2": {"bgp": {"local_as": 0,}},
-        "r3": {"bgp": {"local_as": 0,}},
-        "r4": {"bgp": {"local_as": 64000,}},
+        "r1": {
+            "bgp": {
+                "local_as": 0,
+            }
+        },
+        "r2": {
+            "bgp": {
+                "local_as": 0,
+            }
+        },
+        "r3": {
+            "bgp": {
+                "local_as": 0,
+            }
+        },
+        "r4": {
+            "bgp": {
+                "local_as": 64000,
+            }
+        },
     }
     result = modify_as_number(tgen, topo, input_dict)
     try:
@@ -819,7 +835,11 @@ def test_bgp_with_loopback_interface(request):
             # Adding ['source_link'] = 'lo' key:value pair
             topo["routers"][routerN]["bgp"]["address_family"]["ipv4"]["unicast"][
                 "neighbor"
-            ][bgp_neighbor]["dest_link"] = {"lo": {"source_link": "lo",}}
+            ][bgp_neighbor]["dest_link"] = {
+                "lo": {
+                    "source_link": "lo",
+                }
+            }
 
     # Creating configuration from JSON
     build_config_from_json(tgen, topo)
index 54a3c699f3538fc069fd0db074bd3cfa99192e27..353df0684bace28edfd0ba36518f29560ab724a6 100644 (file)
@@ -273,8 +273,20 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
         "r3": {
             "bgp": {
                 "address_family": {
-                    "ipv4": {"unicast": {"maximum_paths": {"ebgp": ecmp_num,}}},
-                    "ipv6": {"unicast": {"maximum_paths": {"ebgp": ecmp_num,}}},
+                    "ipv4": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ebgp": ecmp_num,
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ebgp": ecmp_num,
+                            }
+                        }
+                    },
                 }
             }
         }
@@ -303,7 +315,7 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
             input_dict_1,
             next_hop=NEXT_HOPS[addr_type][: int(ecmp_num)],
             protocol=protocol,
-            count_only=True
+            count_only=True,
         )
 
         assert result is True, "Testcase {} : Failed \n Error: {}".format(
@@ -312,9 +324,9 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
 
     write_test_footer(tc_name)
 
-
+@pytest.mark.parametrize("ecmp_num", ["8", "16", "32"])
 @pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"])
-def test_ecmp_after_clear_bgp(request, test_type):
+def test_ecmp_after_clear_bgp(request, ecmp_num, test_type):
     """ Verify BGP table and RIB in DUT after clear BGP routes and neighbors"""
 
     tc_name = request.node.name
@@ -337,7 +349,7 @@ def test_ecmp_after_clear_bgp(request, test_type):
             addr_type,
             dut,
             input_dict_1,
-            next_hop=NEXT_HOPS[addr_type],
+            next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)],
             protocol=protocol,
         )
         assert result is True, "Testcase {} : Failed \n Error: {}".format(
@@ -360,7 +372,7 @@ def test_ecmp_after_clear_bgp(request, test_type):
             addr_type,
             dut,
             input_dict_1,
-            next_hop=NEXT_HOPS[addr_type],
+            next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)],
             protocol=protocol,
         )
         assert result is True, "Testcase {} : Failed \n Error: {}".format(
@@ -371,8 +383,8 @@ def test_ecmp_after_clear_bgp(request, test_type):
 
 
 def test_ecmp_remove_redistribute_static(request):
-    """ Verify routes are cleared from BGP and RIB table of DUT when
-        redistribute static configuration is removed."""
+    """Verify routes are cleared from BGP and RIB table of DUT when
+    redistribute static configuration is removed."""
 
     tc_name = request.node.name
     write_test_header(tc_name)
@@ -481,8 +493,8 @@ def test_ecmp_remove_redistribute_static(request):
 
 @pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"])
 def test_ecmp_shut_bgp_neighbor(request, test_type):
-    """ Shut BGP neigbors one by one and verify BGP and routing table updated
-        accordingly in DUT """
+    """Shut BGP neigbors one by one and verify BGP and routing table updated
+    accordingly in DUT"""
 
     tc_name = request.node.name
     write_test_header(tc_name)
index 73724ac069b96c2dadff760143fec7a7ef7ea895..2f73bdb1b825e0530d3de22380e9049764324feb 100644 (file)
@@ -274,8 +274,20 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
         "r3": {
             "bgp": {
                 "address_family": {
-                    "ipv4": {"unicast": {"maximum_paths": {"ibgp": ecmp_num,}}},
-                    "ipv6": {"unicast": {"maximum_paths": {"ibgp": ecmp_num,}}},
+                    "ipv4": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ibgp": ecmp_num,
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ibgp": ecmp_num,
+                            }
+                        }
+                    },
                 }
             }
         }
@@ -304,7 +316,7 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
             input_dict_1,
             next_hop=NEXT_HOPS[addr_type][: int(ecmp_num)],
             protocol=protocol,
-            count_only=True
+            count_only=True,
         )
 
         assert result is True, "Testcase {} : Failed \n Error: {}".format(
@@ -313,9 +325,9 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
 
     write_test_footer(tc_name)
 
-
+@pytest.mark.parametrize("ecmp_num", ["8", "16", "32"])
 @pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"])
-def test_ecmp_after_clear_bgp(request, test_type):
+def test_ecmp_after_clear_bgp(request, ecmp_num, test_type):
     """ Verify BGP table and RIB in DUT after clear BGP routes and neighbors"""
 
     tc_name = request.node.name
@@ -338,7 +350,7 @@ def test_ecmp_after_clear_bgp(request, test_type):
             addr_type,
             dut,
             input_dict_1,
-            next_hop=NEXT_HOPS[addr_type],
+            next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)],
             protocol=protocol,
         )
         assert result is True, "Testcase {} : Failed \n Error: {}".format(
@@ -361,7 +373,7 @@ def test_ecmp_after_clear_bgp(request, test_type):
             addr_type,
             dut,
             input_dict_1,
-            next_hop=NEXT_HOPS[addr_type],
+            next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)],
             protocol=protocol,
         )
         assert result is True, "Testcase {} : Failed \n Error: {}".format(
@@ -372,8 +384,8 @@ def test_ecmp_after_clear_bgp(request, test_type):
 
 
 def test_ecmp_remove_redistribute_static(request):
-    """ Verify routes are cleared from BGP and RIB table of DUT when
-        redistribute static configuration is removed."""
+    """Verify routes are cleared from BGP and RIB table of DUT when
+    redistribute static configuration is removed."""
 
     tc_name = request.node.name
     write_test_header(tc_name)
@@ -482,8 +494,8 @@ def test_ecmp_remove_redistribute_static(request):
 
 @pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"])
 def test_ecmp_shut_bgp_neighbor(request, test_type):
-    """ Shut BGP neigbors one by one and verify BGP and routing table updated
-        accordingly in DUT """
+    """Shut BGP neigbors one by one and verify BGP and routing table updated
+    accordingly in DUT"""
 
     tc_name = request.node.name
     write_test_header(tc_name)
index 4c56d1a02d81cc0ae60694d9c143501657da3d0f..4e37ab00a3e4ddfc9fbc56f15f28ad4660a0c924 100644 (file)
@@ -362,7 +362,7 @@ def config_hosts(tgen, hosts):
         host = tgen.gears[host_name]
         config_host(host_name, host)
 
-
+@pytest.mark.pim
 def setup_module(module):
     "Setup topology"
     tgen = Topogen(NetworkTopo, module.__name__)
@@ -658,10 +658,11 @@ def test_evpn_mac():
         assertmsg = '"{}" remote MAC content incorrect'.format(tor.name)
         assert result is None, assertmsg
 
+
 def check_df_role(dut, esi, role):
-    '''
+    """
     Return error string if the df role on the dut is different
-    '''
+    """
     es_json = dut.vtysh_cmd("show evpn es %s json" % esi)
     es = json.loads(es_json)
 
@@ -676,12 +677,13 @@ def check_df_role(dut, esi, role):
 
     return None
 
+
 def test_evpn_df():
-    '''
+    """
     1. Check the DF role on all the PEs on rack-1.
     2. Increase the DF preference on the non-DF and check if it becomes
        the DF winner.
-    '''
+    """
 
     tgen = get_topogen()
 
@@ -720,10 +722,11 @@ def test_evpn_df():
 
     # tgen.mininet_cli()
 
+
 def check_protodown_rc(dut, protodown_rc):
-    '''
+    """
     check if specified protodown reason code is set
-    '''
+    """
 
     out = dut.vtysh_cmd("show evpn json")
 
@@ -739,13 +742,14 @@ def check_protodown_rc(dut, protodown_rc):
 
     return None
 
+
 def test_evpn_uplink_tracking():
-    '''
+    """
     1. Wait for access ports to come out of startup-delay
     2. disable uplinks and check if access ports have been protodowned
     3. enable uplinks and check if access ports have been moved out
        of protodown
-    '''
+    """
 
     tgen = get_topogen()
 
@@ -778,6 +782,7 @@ def test_evpn_uplink_tracking():
     assertmsg = '"{}" protodown rc incorrect'.format(dut_name)
     assert result is None, assertmsg
 
+
 if __name__ == "__main__":
     args = ["-s"] + sys.argv[1:]
     sys.exit(pytest.main(args))
index 5098808d55d30de53f6d852ee01fcb2ee6b4fec5..9a38158b2be040fe0d290650e63e2b0b6e221a3c 100755 (executable)
@@ -310,8 +310,10 @@ def ip_learn_test(tgen, host, local, remote, ip_addr):
     assertmsg = "local learned mac wrong type: {} ".format(mac_type)
     assert mac_type == "local", assertmsg
 
-    assertmsg = "learned address mismatch with configured address host: {} learned: {}".format(
-        ip_addr, learned_ip
+    assertmsg = (
+        "learned address mismatch with configured address host: {} learned: {}".format(
+            ip_addr, learned_ip
+        )
     )
     assert ip_addr == learned_ip, assertmsg
 
index 607b036c6acc05ff28def375ef67a1bb04701835..a9541a55c5c41bc38de71455d6e953a43f8d1530 100644 (file)
@@ -238,9 +238,10 @@ def test_next_hop_attribute(request):
         result = verify_rib(
             tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
         )
-        assert result is not True, (
-            "Testcase {} : Failed \n Error: "
-            "{} routes are not present in RIB".format(addr_type, tc_name)
+        assert (
+            result is not True
+        ), "Testcase {} : Failed \n Error: " "{} routes are not present in RIB".format(
+            addr_type, tc_name
         )
 
     # Configure next-hop-self to bgp neighbor
index 1aa951edaa81efcb5ab1cea2c26db6484b208dd5..0158e24d313567ab6ca14022d2534b38d481cb84 100644 (file)
@@ -807,7 +807,9 @@ def test_route_map_multiple_seq_different_match_set_clause_p0(request):
                                         "prefix_lists": "pf_list_2_{}".format(addr_type)
                                     }
                                 },
-                                "set": {"locPrf": 150,},
+                                "set": {
+                                    "locPrf": 150,
+                                },
                             },
                             {
                                 "action": "permit",
@@ -906,7 +908,17 @@ def test_route_map_multiple_seq_different_match_set_clause_p0(request):
         dut = "r3"
         protocol = "bgp"
         input_dict = {
-            "r3": {"route_maps": {"rmap_match_pf_list1": [{"set": {"metric": 50,}}],}}
+            "r3": {
+                "route_maps": {
+                    "rmap_match_pf_list1": [
+                        {
+                            "set": {
+                                "metric": 50,
+                            }
+                        }
+                    ],
+                }
+            }
         }
 
         static_routes = [NETWORK[adt][0]]
@@ -1093,7 +1105,14 @@ def test_route_map_set_only_no_match_p0(request):
         input_dict_4 = {
             "r3": {
                 "route_maps": {
-                    "rmap_match_pf_1": [{"action": "permit", "set": {"metric": 50,}}]
+                    "rmap_match_pf_1": [
+                        {
+                            "action": "permit",
+                            "set": {
+                                "metric": 50,
+                            },
+                        }
+                    ]
                 }
             }
         }
@@ -1210,7 +1229,13 @@ def test_route_map_match_only_no_set_p0(request):
                 "r1": {
                     "route_maps": {
                         "rmap_match_pf_1_{}".format(addr_type): [
-                            {"action": "permit", "set": {"metric": 50, "locPrf": 150,}}
+                            {
+                                "action": "permit",
+                                "set": {
+                                    "metric": 50,
+                                    "locPrf": 150,
+                                },
+                            }
                         ]
                     }
                 }
index 3056aa29f37ea5d9b49a8810b408a1dd72a6d602..958eceba62b75cf392cb94e87d12f37ac9d0e5b8 100644 (file)
@@ -268,12 +268,20 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0():
             "prefix_lists": {
                 "ipv4": {
                     "pf_list_1_ipv4": [
-                        {"seqid": 10, "network": "any", "action": "permit",}
+                        {
+                            "seqid": 10,
+                            "network": "any",
+                            "action": "permit",
+                        }
                     ]
                 },
                 "ipv6": {
                     "pf_list_1_ipv6": [
-                        {"seqid": 10, "network": "any", "action": "permit",}
+                        {
+                            "seqid": 10,
+                            "network": "any",
+                            "action": "permit",
+                        }
                     ]
                 },
             }
@@ -472,7 +480,11 @@ def test_modify_set_match_clauses_in_rmap_p0():
             "prefix_lists": {
                 "ipv4": {
                     "pf_list_1_ipv4": [
-                        {"seqid": 10, "network": "any", "action": "permit",}
+                        {
+                            "seqid": 10,
+                            "network": "any",
+                            "action": "permit",
+                        }
                     ],
                     "pf_list_2_ipv4": [
                         {"seqid": 10, "network": "any", "action": "permit"}
@@ -480,7 +492,11 @@ def test_modify_set_match_clauses_in_rmap_p0():
                 },
                 "ipv6": {
                     "pf_list_1_ipv6": [
-                        {"seqid": 10, "network": "any", "action": "permit",}
+                        {
+                            "seqid": 10,
+                            "network": "any",
+                            "action": "permit",
+                        }
                     ],
                     "pf_list_2_ipv6": [
                         {"seqid": 10, "network": "any", "action": "permit"}
@@ -506,7 +522,9 @@ def test_modify_set_match_clauses_in_rmap_p0():
                                     "prefix_lists": "pf_list_1_{}".format(addr_type)
                                 }
                             },
-                            "set": {"locPrf": 150,},
+                            "set": {
+                                "locPrf": 150,
+                            },
                         }
                     ],
                     "rmap_match_pf_2_{}".format(addr_type): [
@@ -666,7 +684,9 @@ def test_modify_set_match_clauses_in_rmap_p0():
                                     "prefix_lists": "pf_list_1_{}".format(addr_type)
                                 }
                             },
-                            "set": {"locPrf": 1000,},
+                            "set": {
+                                "locPrf": 1000,
+                            },
                         }
                     ],
                     "rmap_match_pf_2_{}".format(addr_type): [
@@ -816,12 +836,20 @@ def test_modify_prefix_list_referenced_by_rmap_p0():
             "prefix_lists": {
                 "ipv4": {
                     "pf_list_1_ipv4": [
-                        {"seqid": 10, "network": "any", "action": "permit",}
+                        {
+                            "seqid": 10,
+                            "network": "any",
+                            "action": "permit",
+                        }
                     ]
                 },
                 "ipv6": {
                     "pf_list_1_ipv6": [
-                        {"seqid": 100, "network": "any", "action": "permit",}
+                        {
+                            "seqid": 100,
+                            "network": "any",
+                            "action": "permit",
+                        }
                     ]
                 },
             }
@@ -1090,7 +1118,9 @@ def test_remove_prefix_list_referenced_by_rmap_p0():
                                     "prefix_lists": "pf_list_1_{}".format(addr_type)
                                 }
                             },
-                            "set": {"locPrf": 150,},
+                            "set": {
+                                "locPrf": 150,
+                            },
                         }
                     ],
                     "rmap_match_pf_2_{}".format(addr_type): [
@@ -1894,7 +1924,9 @@ def test_multiple_match_statement_in_route_map_logical_ANDed_p1():
                                     "prefix_lists": "pf_list_1_{}".format(addr_type)
                                 }
                             },
-                            "set": {"locPrf": 150,},
+                            "set": {
+                                "locPrf": 150,
+                            },
                         }
                     ]
                 }
@@ -1921,7 +1953,9 @@ def test_multiple_match_statement_in_route_map_logical_ANDed_p1():
                                     }
                                 }
                             },
-                            "set": {"locPrf": 150,},
+                            "set": {
+                                "locPrf": 150,
+                            },
                         }
                     ]
                 }
@@ -2048,7 +2082,9 @@ def test_add_remove_rmap_to_specific_neighbor_p0():
                                     "prefix_lists": "pf_list_1_{}".format(addr_type)
                                 }
                             },
-                            "set": {"locPrf": 150,},
+                            "set": {
+                                "locPrf": 150,
+                            },
                         }
                     ]
                 }
@@ -3505,7 +3541,9 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0():
                                     "prefix_lists": "pf_list_1_{}".format(addr_type)
                                 }
                             },
-                            "set": {"locPrf": 150,},
+                            "set": {
+                                "locPrf": 150,
+                            },
                         }
                     ],
                     "rmap_match_pf_2_{}".format(addr_type): [
index 36f1d8cd566c009671d0e9a548135102c374786a..71f64e9b706aa7324a287639cf7efc5c3483a29b 100644 (file)
@@ -90,7 +90,11 @@ def test_vrf_route_leak():
 
     # Test DONNA VRF.
     expect = {
-        "10.0.0.0/24": [{"protocol": "connected",}],
+        "10.0.0.0/24": [
+            {
+                "protocol": "connected",
+            }
+        ],
         "10.0.1.0/24": [
             {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
         ],
@@ -111,11 +115,19 @@ def test_vrf_route_leak():
         "10.0.0.0/24": [
             {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
         ],
-        "10.0.1.0/24": [{"protocol": "connected",}],
+        "10.0.1.0/24": [
+            {
+                "protocol": "connected",
+            }
+        ],
         "10.0.2.0/24": [
             {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
         ],
-        "10.0.3.0/24": [{"protocol": "connected",}],
+        "10.0.3.0/24": [
+            {
+                "protocol": "connected",
+            }
+        ],
     }
 
     test_func = partial(
diff --git a/tests/topotests/bgp_community_change_update/__init__.py b/tests/topotests/bgp_community_change_update/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bgp_community_change_update/c1/bgpd.conf b/tests/topotests/bgp_community_change_update/c1/bgpd.conf
new file mode 100644 (file)
index 0000000..24cf9df
--- /dev/null
@@ -0,0 +1,11 @@
+!
+debug bgp updates
+!
+router bgp 65001
+  no bgp ebgp-requires-policy
+  neighbor 10.0.1.2 remote-as external
+  neighbor 10.0.1.2 timers 3 10
+  address-family ipv4 unicast
+    redistribute connected
+  exit-address-family
+!
diff --git a/tests/topotests/bgp_community_change_update/c1/zebra.conf b/tests/topotests/bgp_community_change_update/c1/zebra.conf
new file mode 100644 (file)
index 0000000..e3dbbc0
--- /dev/null
@@ -0,0 +1,6 @@
+!
+interface c1-eth0
+ ip address 10.0.1.1/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py b/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py
new file mode 100644 (file)
index 0000000..5fc4310
--- /dev/null
@@ -0,0 +1,225 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2020 by
+# Donatas Abraitis <donatas.abraitis@gmail.com>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Reference: https://www.cmand.org/communityexploration
+
+                     --y2--
+                    /  |   \
+  c1 ---- x1 ---- y1   |   z1
+                    \  |   /
+                     --y3--
+
+1. z1 announces 192.168.255.254/32 to y2, y3.
+2. y2 and y3 tags this prefix at ingress with appropriate
+communities 65004:2 (y2) and 65004:3 (y3).
+3. x1 filters all communities at the egress to c1.
+4. Shutdown the link between y1 and y2.
+5. y1 will generate a BGP UPDATE message regarding the next-hop change.
+6. x1 will generate a BGP UPDATE message regarding community change.
+
+To avoid sending duplicate BGP UPDATE messages we should make sure
+we send only actual route updates. In this example, x1 will skip
+BGP UPDATE to c1 because the actual route is the same
+(filtered communities - nothing changes).
+"""
+
+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
+from mininet.topo import Topo
+
+from lib.common_config import step
+from time import sleep
+
+
+class TemplateTopo(Topo):
+    def build(self, *_args, **_opts):
+        tgen = get_topogen(self)
+
+        tgen.add_router("z1")
+        tgen.add_router("y1")
+        tgen.add_router("y2")
+        tgen.add_router("y3")
+        tgen.add_router("x1")
+        tgen.add_router("c1")
+
+        # 10.0.1.0/30
+        switch = tgen.add_switch("s1")
+        switch.add_link(tgen.gears["c1"])
+        switch.add_link(tgen.gears["x1"])
+
+        # 10.0.2.0/30
+        switch = tgen.add_switch("s2")
+        switch.add_link(tgen.gears["x1"])
+        switch.add_link(tgen.gears["y1"])
+
+        # 10.0.3.0/30
+        switch = tgen.add_switch("s3")
+        switch.add_link(tgen.gears["y1"])
+        switch.add_link(tgen.gears["y2"])
+
+        # 10.0.4.0/30
+        switch = tgen.add_switch("s4")
+        switch.add_link(tgen.gears["y1"])
+        switch.add_link(tgen.gears["y3"])
+
+        # 10.0.5.0/30
+        switch = tgen.add_switch("s5")
+        switch.add_link(tgen.gears["y2"])
+        switch.add_link(tgen.gears["y3"])
+
+        # 10.0.6.0/30
+        switch = tgen.add_switch("s6")
+        switch.add_link(tgen.gears["y2"])
+        switch.add_link(tgen.gears["z1"])
+
+        # 10.0.7.0/30
+        switch = tgen.add_switch("s7")
+        switch.add_link(tgen.gears["y3"])
+        switch.add_link(tgen.gears["z1"])
+
+
+def setup_module(mod):
+    tgen = Topogen(TemplateTopo, 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_community_update_path_change():
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    def _bgp_converge_initial():
+        output = json.loads(
+            tgen.gears["c1"].vtysh_cmd("show ip bgp neighbor 10.0.1.2 json")
+        )
+        expected = {
+            "10.0.1.2": {
+                "bgpState": "Established",
+                "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 8}},
+            }
+        }
+        return topotest.json_cmp(output, expected)
+
+    step("Check if an initial topology is converged")
+    test_func = functools.partial(_bgp_converge_initial)
+    success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+    assert result is None, "Failed to see bgp convergence in c1"
+
+    step("Disable link between y1 and y2")
+    tgen.gears["y1"].run("ip link set dev y1-eth1 down")
+
+    def _bgp_converge_link_disabled():
+        output = json.loads(tgen.gears["y1"].vtysh_cmd("show ip bgp nei 10.0.3.2 json"))
+        expected = {"10.0.3.2": {"bgpState": "Active"}}
+        return topotest.json_cmp(output, expected)
+
+    step("Check if a topology is converged after a link down between y1 and y2")
+    test_func = functools.partial(_bgp_converge_link_disabled)
+    success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+    assert result is None, "Failed to see bgp convergence in y1"
+
+    def _bgp_check_for_duplicate_updates():
+        duplicate = False
+        i = 0
+        while i < 5:
+            if (
+                len(
+                    tgen.gears["c1"].run(
+                        'grep "10.0.1.2 rcvd 192.168.255.254/32 IPv4 unicast...duplicate ignored" bgpd.log'
+                    )
+                )
+                > 0
+            ):
+                duplicate = True
+            i += 1
+            sleep(0.5)
+        return duplicate
+
+    step("Check if we see duplicate BGP UPDATE message in c1 (suppress-duplicates)")
+    assert (
+        _bgp_check_for_duplicate_updates() == False
+    ), "Seen duplicate BGP UPDATE message in c1 from x1"
+
+    step("Disable bgp suppress-duplicates at x1")
+    tgen.gears["x1"].run(
+        "vtysh -c 'conf' -c 'router bgp' -c 'no bgp suppress-duplicates'"
+    )
+
+    step("Enable link between y1 and y2")
+    tgen.gears["y1"].run("ip link set dev y1-eth1 up")
+
+    def _bgp_converge_link_enabled():
+        output = json.loads(tgen.gears["y1"].vtysh_cmd("show ip bgp nei 10.0.3.2 json"))
+        expected = {
+            "10.0.3.2": {
+                "bgpState": "Established",
+                "addressFamilyInfo": {
+                    "ipv4Unicast": {"acceptedPrefixCounter": 5, "sentPrefixCounter": 4}
+                },
+            }
+        }
+        return topotest.json_cmp(output, expected)
+
+    step("Check if a topology is converged after a link up between y1 and y2")
+    test_func = functools.partial(_bgp_converge_link_enabled)
+    success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+    assert result is None, "Failed to see bgp convergence in y1"
+
+    step(
+        "Check if we see duplicate BGP UPDATE message in c1 (no bgp suppress-duplicates)"
+    )
+    assert (
+        _bgp_check_for_duplicate_updates() == True
+    ), "Didn't see duplicate BGP UPDATE message in c1 from x1"
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_community_change_update/x1/bgpd.conf b/tests/topotests/bgp_community_change_update/x1/bgpd.conf
new file mode 100644 (file)
index 0000000..8d7bcb9
--- /dev/null
@@ -0,0 +1,20 @@
+!
+debug bgp updates
+!
+router bgp 65002
+  no bgp ebgp-requires-policy
+  neighbor 10.0.1.1 remote-as external
+  neighbor 10.0.1.1 timers 3 10
+  neighbor 10.0.2.2 remote-as external
+  neighbor 10.0.2.2 timers 3 10
+  address-family ipv4 unicast
+    redistribute connected
+    neighbor 10.0.1.1 route-map c1 out
+  exit-address-family
+!
+bgp community-list standard c1 seq 1 permit 65004:2
+bgp community-list standard c1 seq 2 permit 65004:3
+!
+route-map c1 permit 10
+  set comm-list c1 delete
+!
diff --git a/tests/topotests/bgp_community_change_update/x1/zebra.conf b/tests/topotests/bgp_community_change_update/x1/zebra.conf
new file mode 100644 (file)
index 0000000..8b7c03f
--- /dev/null
@@ -0,0 +1,9 @@
+!
+interface x1-eth0
+ ip address 10.0.1.2/30
+!
+interface x1-eth1
+ ip address 10.0.2.1/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_community_change_update/y1/bgpd.conf b/tests/topotests/bgp_community_change_update/y1/bgpd.conf
new file mode 100644 (file)
index 0000000..a010085
--- /dev/null
@@ -0,0 +1,12 @@
+router bgp 65003
+  no bgp ebgp-requires-policy
+  neighbor 10.0.2.1 remote-as external
+  neighbor 10.0.2.1 timers 3 10
+  neighbor 10.0.3.2 remote-as internal
+  neighbor 10.0.3.2 timers 3 10
+  neighbor 10.0.4.2 remote-as internal
+  neighbor 10.0.4.2 timers 3 10
+  address-family ipv4 unicast
+    redistribute connected
+  exit-address-family
+!
diff --git a/tests/topotests/bgp_community_change_update/y1/zebra.conf b/tests/topotests/bgp_community_change_update/y1/zebra.conf
new file mode 100644 (file)
index 0000000..4096f2a
--- /dev/null
@@ -0,0 +1,12 @@
+!
+interface y1-eth0
+ ip address 10.0.2.2/30
+!
+interface y1-eth1
+ ip address 10.0.3.1/30
+!
+interface y1-eth2
+ ip address 10.0.4.1/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_community_change_update/y2/bgpd.conf b/tests/topotests/bgp_community_change_update/y2/bgpd.conf
new file mode 100644 (file)
index 0000000..27f1e81
--- /dev/null
@@ -0,0 +1,18 @@
+router bgp 65003
+  no bgp ebgp-requires-policy
+  neighbor 10.0.3.1 remote-as internal
+  neighbor 10.0.3.1 timers 3 10
+  neighbor 10.0.5.2 remote-as internal
+  neighbor 10.0.5.2 timers 3 10
+  neighbor 10.0.6.2 remote-as external
+  neighbor 10.0.6.2 timers 3 10
+  address-family ipv4 unicast
+    redistribute connected
+    neighbor 10.0.3.1 route-reflector-client
+    neighbor 10.0.5.2 route-reflector-client
+    neighbor 10.0.6.2 route-map z1 in
+  exit-address-family
+!
+route-map z1 permit 10
+  set community 65004:2
+!
diff --git a/tests/topotests/bgp_community_change_update/y2/zebra.conf b/tests/topotests/bgp_community_change_update/y2/zebra.conf
new file mode 100644 (file)
index 0000000..7e9458a
--- /dev/null
@@ -0,0 +1,12 @@
+!
+interface y2-eth0
+ ip address 10.0.3.2/30
+!
+interface y2-eth1
+ ip address 10.0.5.1/30
+!
+interface y2-eth2
+ ip address 10.0.6.1/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_community_change_update/y3/bgpd.conf b/tests/topotests/bgp_community_change_update/y3/bgpd.conf
new file mode 100644 (file)
index 0000000..8e57284
--- /dev/null
@@ -0,0 +1,18 @@
+router bgp 65003
+  no bgp ebgp-requires-policy
+  neighbor 10.0.4.1 remote-as internal
+  neighbor 10.0.4.1 timers 3 10
+  neighbor 10.0.5.1 remote-as internal
+  neighbor 10.0.5.1 timers 3 10
+  neighbor 10.0.7.2 remote-as external
+  neighbor 10.0.7.2 timers 3 10
+  address-family ipv4 unicast
+    redistribute connected
+    neighbor 10.0.4.1 route-reflector-client
+    neighbor 10.0.5.1 route-reflector-client
+    neighbor 10.0.7.2 route-map z1 in
+  exit-address-family
+!
+route-map z1 permit 10
+  set community 65004:3
+!
diff --git a/tests/topotests/bgp_community_change_update/y3/zebra.conf b/tests/topotests/bgp_community_change_update/y3/zebra.conf
new file mode 100644 (file)
index 0000000..93dd87d
--- /dev/null
@@ -0,0 +1,12 @@
+!
+interface y3-eth0
+ ip address 10.0.4.2/30
+!
+interface y3-eth1
+ ip address 10.0.5.2/30
+!
+interface y3-eth2
+ ip address 10.0.7.1/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_community_change_update/z1/bgpd.conf b/tests/topotests/bgp_community_change_update/z1/bgpd.conf
new file mode 100644 (file)
index 0000000..2f470f1
--- /dev/null
@@ -0,0 +1,10 @@
+router bgp 65004
+  no bgp ebgp-requires-policy
+  neighbor 10.0.6.1 remote-as external
+  neighbor 10.0.6.1 timers 3 10
+  neighbor 10.0.7.1 remote-as external
+  neighbor 10.0.7.1 timers 3 10
+  address-family ipv4 unicast
+    redistribute connected
+  exit-address-family
+!
diff --git a/tests/topotests/bgp_community_change_update/z1/zebra.conf b/tests/topotests/bgp_community_change_update/z1/zebra.conf
new file mode 100644 (file)
index 0000000..7f6bbb6
--- /dev/null
@@ -0,0 +1,12 @@
+!
+interface lo
+ ip address 192.168.255.254/32
+!
+interface z1-eth0
+ ip address 10.0.6.2/30
+!
+interface z1-eth1
+ ip address 10.0.7.2/30
+!
+ip forwarding
+!
index 003193f108d21940e97b23dc50d483dcb548bca5..fa155dd5fe43201c837ddb95975511f0c9e42f53 100644 (file)
@@ -31,9 +31,11 @@ to send advertisements.
 Scenario 1:
   r1 has a filter applied for outgoing direction,
   r2 receives 192.168.255.1/32.
+
 Scenario 2:
   r3 hasn't a filter appied for outgoing direction,
   r4 does not receive 192.168.255.1/32.
+
 Scenario 3:
   r5 and r6 establish iBGP session which in turn should ignore
   RFC8212. All routes for both directions MUST work.
@@ -63,14 +65,17 @@ class TemplateTopo(Topo):
         for routern in range(1, 7):
             tgen.add_router("r{}".format(routern))
 
+        # Scenario 1.
         switch = tgen.add_switch("s1")
         switch.add_link(tgen.gears["r1"])
         switch.add_link(tgen.gears["r2"])
 
+        # Scenario 2.
         switch = tgen.add_switch("s2")
         switch.add_link(tgen.gears["r3"])
         switch.add_link(tgen.gears["r4"])
 
+        # Scenario 3.
         switch = tgen.add_switch("s3")
         switch.add_link(tgen.gears["r5"])
         switch.add_link(tgen.gears["r6"])
@@ -120,41 +125,48 @@ def test_ebgp_requires_policy():
         expected = {"routes": {"172.16.255.254/32": [{"valid": True}]}}
         return topotest.json_cmp(output, expected)
 
+    def _bgp_advertised_routes(router):
+        output = json.loads(
+            tgen.gears[router].vtysh_cmd(
+                "show ip bgp neighbor 192.168.255.2 advertised-routes json"
+            )
+        )
+        expected = {
+            "advertisedRoutes": {},
+            "totalPrefixCounter": 0,
+            "filteredPrefixCounter": 0,
+        }
+        return topotest.json_cmp(output, expected)
+
+    # Scenario 1.
+    logger.info("Scenario 1: r2 receives 192.168.255.1/32 from r1")
     test_func = functools.partial(_bgp_converge, "r2")
-    success, result = topotest.run_and_expect(test_func, None, count=65, wait=2)
-    assert success is True, 'Failed bgp convergence (r2) in "{}"'.format(
-        tgen.gears["r2"]
-    )
+    success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
+    assert success is True, "Failed bgp convergence (r2)"
 
     test_func = functools.partial(_bgp_has_routes, "r2")
-    success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
-    assert success is True, 'eBGP policy is not working (r2) in "{}"'.format(
-        tgen.gears["r2"]
-    )
+    success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
+    assert success is True, "r2 does not receive 192.168.255.1/32"
 
+    # Scenario 2.
+    logger.info("Scenario 2: r3 must not send 192.168.255.1/32 to r4")
     test_func = functools.partial(_bgp_converge, "r4")
-    success, result = topotest.run_and_expect(test_func, None, count=65, wait=2)
-    assert success is True, 'Failed bgp convergence (r4) in "{}"'.format(
-        tgen.gears["r4"]
-    )
+    success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
+    assert success is True, "Failed bgp convergence (r4)"
 
-    test_func = functools.partial(_bgp_has_routes, "r4")
-    success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
-    assert success is False, 'eBGP policy is not working (r4) in "{}"'.format(
-        tgen.gears["r4"]
-    )
+    test_func = functools.partial(_bgp_advertised_routes, "r3")
+    success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
+    assert success is True, "r3 announced 192.168.255.1/32 to r4"
 
+    # Scenario 3.
+    logger.info("Scenario 3: r6 receives 192.168.255.1/32 from r5 (iBGP)")
     test_func = functools.partial(_bgp_converge, "r6")
-    success, result = topotest.run_and_expect(test_func, None, count=65, wait=2)
-    assert success is True, 'Failed bgp convergence (r6) in "{}"'.format(
-        tgen.gears["r6"]
-    )
+    success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
+    assert success is True, "Failed bgp convergence (r6)"
 
     test_func = functools.partial(_bgp_has_routes, "r6")
-    success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
-    assert success is True, 'eBGP policy is not working (r6) in "{}"'.format(
-        tgen.gears["r6"]
-    )
+    success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
+    assert success is True, "r6 does not receive 192.168.255.1/32"
 
 
 if __name__ == "__main__":
diff --git a/tests/topotests/bgp_features/exabgp.env b/tests/topotests/bgp_features/exabgp.env
new file mode 100644 (file)
index 0000000..6c554f5
--- /dev/null
@@ -0,0 +1,53 @@
+
+[exabgp.api]
+encoder = text
+highres = false
+respawn = false
+socket = ''
+
+[exabgp.bgp]
+openwait = 60
+
+[exabgp.cache]
+attributes = true
+nexthops = true
+
+[exabgp.daemon]
+daemonize = true
+pid = '/var/run/exabgp/exabgp.pid'
+user = 'exabgp'
+
+[exabgp.log]
+all = false
+configuration = true
+daemon = true
+destination = '/var/log/exabgp.log'
+enable = true
+level = INFO
+message = false
+network = true
+packets = false
+parser = false
+processes = true
+reactor = true
+rib = false
+routes = false
+short = false
+timers = false
+
+[exabgp.pdb]
+enable = false
+
+[exabgp.profile]
+enable = false
+file = ''
+
+[exabgp.reactor]
+speed = 1.0
+
+[exabgp.tcp]
+acl = false
+bind = ''
+delay = 0
+once = false
+port = 179
diff --git a/tests/topotests/bgp_features/peer1/exa_readpipe.py b/tests/topotests/bgp_features/peer1/exa_readpipe.py
new file mode 100644 (file)
index 0000000..dba1536
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+"Helper script to read api commands from a pipe and feed them to ExaBGP"
+
+import sys
+
+if len(sys.argv) != 2:
+    sys.exit(1)
+fifo = sys.argv[1]
+
+while True:
+    pipe = open(fifo, 'r')
+    with pipe:
+        line = pipe.readline().strip()
+        if line != "":
+            sys.stdout.write("{}\n".format(line))
+            sys.stdout.flush()
+        pipe.close()
+
+sys.exit(0)
diff --git a/tests/topotests/bgp_features/peer1/exabgp.cfg b/tests/topotests/bgp_features/peer1/exabgp.cfg
new file mode 100644 (file)
index 0000000..2e95252
--- /dev/null
@@ -0,0 +1,12 @@
+group exabgp {
+        process announce-routes {
+                run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer1.in";
+                encoder text;
+        }
+        neighbor 192.168.101.1 {
+                router-id 192.168.101.3;
+                local-address 192.168.101.3;
+                local-as 65403;
+                peer-as 65000;
+        }
+}
diff --git a/tests/topotests/bgp_features/peer2/exa_readpipe.py b/tests/topotests/bgp_features/peer2/exa_readpipe.py
new file mode 100644 (file)
index 0000000..dba1536
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+"Helper script to read api commands from a pipe and feed them to ExaBGP"
+
+import sys
+
+if len(sys.argv) != 2:
+    sys.exit(1)
+fifo = sys.argv[1]
+
+while True:
+    pipe = open(fifo, 'r')
+    with pipe:
+        line = pipe.readline().strip()
+        if line != "":
+            sys.stdout.write("{}\n".format(line))
+            sys.stdout.flush()
+        pipe.close()
+
+sys.exit(0)
diff --git a/tests/topotests/bgp_features/peer2/exabgp.cfg b/tests/topotests/bgp_features/peer2/exabgp.cfg
new file mode 100644 (file)
index 0000000..1f65547
--- /dev/null
@@ -0,0 +1,12 @@
+group exabgp {
+        process announce-routes {
+                run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer2.in";
+                encoder text;
+        }
+        neighbor 192.168.101.1 {
+                router-id 192.168.101.4;
+                local-address 192.168.101.4;
+                local-as 65404;
+                peer-as 65000;
+        }
+}
diff --git a/tests/topotests/bgp_features/peer3/exa_readpipe.py b/tests/topotests/bgp_features/peer3/exa_readpipe.py
new file mode 100644 (file)
index 0000000..dba1536
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+"Helper script to read api commands from a pipe and feed them to ExaBGP"
+
+import sys
+
+if len(sys.argv) != 2:
+    sys.exit(1)
+fifo = sys.argv[1]
+
+while True:
+    pipe = open(fifo, 'r')
+    with pipe:
+        line = pipe.readline().strip()
+        if line != "":
+            sys.stdout.write("{}\n".format(line))
+            sys.stdout.flush()
+        pipe.close()
+
+sys.exit(0)
diff --git a/tests/topotests/bgp_features/peer3/exabgp.cfg b/tests/topotests/bgp_features/peer3/exabgp.cfg
new file mode 100644 (file)
index 0000000..8632cc8
--- /dev/null
@@ -0,0 +1,12 @@
+group exabgp {
+        process announce-routes {
+                run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer3.in";
+                encoder text;
+        }
+        neighbor 192.168.101.1 {
+                router-id 192.168.101.5;
+                local-address 192.168.101.5;
+                local-as 65405;
+                peer-as 65000;
+        }
+}
diff --git a/tests/topotests/bgp_features/peer4/exa_readpipe.py b/tests/topotests/bgp_features/peer4/exa_readpipe.py
new file mode 100644 (file)
index 0000000..dba1536
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+"Helper script to read api commands from a pipe and feed them to ExaBGP"
+
+import sys
+
+if len(sys.argv) != 2:
+    sys.exit(1)
+fifo = sys.argv[1]
+
+while True:
+    pipe = open(fifo, 'r')
+    with pipe:
+        line = pipe.readline().strip()
+        if line != "":
+            sys.stdout.write("{}\n".format(line))
+            sys.stdout.flush()
+        pipe.close()
+
+sys.exit(0)
diff --git a/tests/topotests/bgp_features/peer4/exabgp.cfg b/tests/topotests/bgp_features/peer4/exabgp.cfg
new file mode 100644 (file)
index 0000000..06bc0d6
--- /dev/null
@@ -0,0 +1,12 @@
+group exabgp {
+        process announce-routes {
+                run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer4.in";
+                encoder text;
+        }
+        neighbor 192.168.101.1 {
+                router-id 192.168.101.6;
+                local-address 192.168.101.6;
+                local-as 65406;
+                peer-as 65000;
+        }
+}
diff --git a/tests/topotests/bgp_features/r1/bgp_damp_announced.json b/tests/topotests/bgp_features/r1/bgp_damp_announced.json
new file mode 100644 (file)
index 0000000..cb4a2c9
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "localAS":65000,
+  "routes":{
+    "192.168.31.0/24": [ { "valid":true, "network":"192.168.31.0\/24", "peerId":"192.168.101.3" } ],
+    "192.168.32.0/24": [ { "valid":true, "network":"192.168.32.0\/24", "peerId":"192.168.101.3" } ],
+    "192.168.33.0/24": [ { "valid":true, "network":"192.168.33.0\/24", "peerId":"192.168.101.3" } ],
+    "192.168.34.0/24": [ { "valid":true, "network":"192.168.34.0\/24", "peerId":"192.168.101.3" } ],
+    "192.168.41.0/24": [ { "valid":true, "network":"192.168.41.0\/24", "peerId":"192.168.101.4" } ],
+    "192.168.42.0/24": [ { "valid":true, "network":"192.168.42.0\/24", "peerId":"192.168.101.4" } ],
+    "192.168.43.0/24": [ { "valid":true, "network":"192.168.43.0\/24", "peerId":"192.168.101.4" } ],
+    "192.168.44.0/24": [ { "valid":true, "network":"192.168.44.0\/24", "peerId":"192.168.101.4" } ],
+    "192.168.51.0/24": [ { "valid":true, "network":"192.168.51.0\/24", "peerId":"192.168.101.5" } ],
+    "192.168.52.0/24": [ { "valid":true, "network":"192.168.52.0\/24", "peerId":"192.168.101.5" } ],
+    "192.168.53.0/24": [ { "valid":true, "network":"192.168.53.0\/24", "peerId":"192.168.101.5" } ],
+    "192.168.54.0/24": [ { "valid":true, "network":"192.168.54.0\/24", "peerId":"192.168.101.5" } ],
+    "192.168.61.0/24": [ { "valid":true, "network":"192.168.61.0\/24", "peerId":"192.168.101.6" } ],
+    "192.168.62.0/24": [ { "valid":true, "network":"192.168.62.0\/24", "peerId":"192.168.101.6" } ],
+    "192.168.63.0/24": [ { "valid":true, "network":"192.168.63.0\/24", "peerId":"192.168.101.6" } ],
+    "192.168.64.0/24": [ { "valid":true, "network":"192.168.64.0\/24", "peerId":"192.168.101.6" } ]
+  }
+}
diff --git a/tests/topotests/bgp_features/r1/bgp_damp_setup.json b/tests/topotests/bgp_features/r1/bgp_damp_setup.json
new file mode 100644 (file)
index 0000000..f9f89db
--- /dev/null
@@ -0,0 +1,10 @@
+{
+  "ipv4Unicast":{
+    "peers":{
+      "192.168.101.3":{"remoteAs":65403, "state":"Established"},
+      "192.168.101.4":{"remoteAs":65404, "state":"Established"},
+      "192.168.101.5":{"remoteAs":65405, "state":"Established"},
+      "192.168.101.6":{"remoteAs":65406, "state":"Established"}
+    }
+  }
+}
diff --git a/tests/topotests/bgp_features/r1/bgp_delayopen_neighbor.json b/tests/topotests/bgp_features/r1/bgp_delayopen_neighbor.json
new file mode 100644 (file)
index 0000000..5caaeab
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "192.168.101.2":{
+    "remoteAs":65100,
+    "bgpTimerDelayOpenTimeMsecs":240000
+  }
+}
diff --git a/tests/topotests/bgp_features/r1/bgp_delayopen_summary_established.json b/tests/topotests/bgp_features/r1/bgp_delayopen_summary_established.json
new file mode 100644 (file)
index 0000000..3ab3588
--- /dev/null
@@ -0,0 +1,11 @@
+{
+"ipv4Unicast":{
+  "as":65000,
+  "peers":{
+    "192.168.101.2":{
+      "remoteAs":65100,
+      "state":"Established"
+    }
+  }
+}
+}
diff --git a/tests/topotests/bgp_features/r1/bgp_delayopen_summary_shutdown.json b/tests/topotests/bgp_features/r1/bgp_delayopen_summary_shutdown.json
new file mode 100644 (file)
index 0000000..9a41236
--- /dev/null
@@ -0,0 +1,11 @@
+{
+"ipv4Unicast":{
+  "as":65000,
+  "peers":{
+    "192.168.101.2":{
+      "remoteAs":65100,
+      "state":"Idle (Admin)"
+    }
+  }
+}
+}
index 532da39fb73c906a1dd50489f5217883068b77f2..a38e4b862a8842abd06134182cf0bf310cadee02 100644 (file)
@@ -4,17 +4,16 @@ debug ospf6 neighbor
 !
 interface r1-lo
 !
-interface r1-eth0
-!
 interface r1-eth1
+ ipv6 ospf6 priority 10
 !
 interface r1-eth2
+ ipv6 ospf6 priority 10
 !
 router ospf6
  ospf6 router-id 192.168.0.1
  log-adjacency-changes
  interface r1-lo area 0.0.0.0
- interface r1-eth0 area 0.0.0.0
  interface r1-eth1 area 0.0.0.0
  interface r1-eth2 area 0.0.0.0
 !
index ecb97d8d7412ac1b92d59d291bcffcaed7097ca7..e742c119dadd23d42038874e5a204cf557ae6300 100644 (file)
@@ -2,14 +2,14 @@
   "neighbors":{
     "192.168.0.2":[
       {
-        "priority":1,
-        "state":"Full\/DR"
+        "priority":5,
+        "state":"Full\/Backup"
       }
     ],
     "192.168.0.3":[
       {
-        "priority":1,
-        "state":"Full\/DR"
+        "priority":5,
+        "state":"Full\/Backup"
       }
     ]
   }
index 8f1711db7b762e61b2b8502de58fcbb2d13ed02f..68a1bb5c75673c8463d5de0f1dd85ef96154f00f 100644 (file)
@@ -3,6 +3,16 @@ log file ospfd.log
 debug ospf event
 debug ospf zebra
 !
+interface r1-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+ ip ospf priority 10
+!
+interface r1-eth2
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+ ip ospf priority 10
+!
 router ospf
  ospf router-id 192.168.0.1
  log-adjacency-changes
@@ -13,11 +23,4 @@ router ospf
  refresh timer 10
 !
 line vty
-interface r1-eth1
- ip ospf hello-interval 2
- ip ospf dead-interval 10
-!
-interface r1-eth2
- ip ospf hello-interval 2
- ip ospf dead-interval 10
 !
diff --git a/tests/topotests/bgp_features/r2/bgp_damp_announced.json b/tests/topotests/bgp_features/r2/bgp_damp_announced.json
new file mode 100644 (file)
index 0000000..9394358
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "localAS":65000,
+  "routes":{
+    "192.168.31.0/24": [ { "network":"192.168.31.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.32.0/24": [ { "network":"192.168.32.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.33.0/24": [ { "network":"192.168.33.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.34.0/24": [ { "network":"192.168.34.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.41.0/24": [ { "network":"192.168.41.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.42.0/24": [ { "network":"192.168.42.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.43.0/24": [ { "network":"192.168.43.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.44.0/24": [ { "network":"192.168.44.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.51.0/24": [ { "network":"192.168.51.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.52.0/24": [ { "network":"192.168.52.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.53.0/24": [ { "network":"192.168.53.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.54.0/24": [ { "network":"192.168.54.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.61.0/24": [ { "network":"192.168.61.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.62.0/24": [ { "network":"192.168.62.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.63.0/24": [ { "network":"192.168.63.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.64.0/24": [ { "network":"192.168.64.0\/24", "peerId":"192.168.0.1" } ]
+  }
+}
diff --git a/tests/topotests/bgp_features/r2/bgp_damp_withdrawn.json b/tests/topotests/bgp_features/r2/bgp_damp_withdrawn.json
new file mode 100644 (file)
index 0000000..f3c54a7
--- /dev/null
@@ -0,0 +1,18 @@
+{
+  "192.168.31.0/24": null,
+  "192.168.32.0/24": null,
+  "192.168.33.0/24": null,
+  "192.168.34.0/24": null,
+  "192.168.41.0/24": null,
+  "192.168.42.0/24": null,
+  "192.168.43.0/24": null,
+  "192.168.44.0/24": null,
+  "192.168.51.0/24": null,
+  "192.168.52.0/24": null,
+  "192.168.53.0/24": null,
+  "192.168.54.0/24": null,
+  "192.168.61.0/24": null,
+  "192.168.62.0/24": null,
+  "192.168.63.0/24": null,
+  "192.168.64.0/24": null
+}
diff --git a/tests/topotests/bgp_features/r2/bgp_delayopen_neighbor.json b/tests/topotests/bgp_features/r2/bgp_delayopen_neighbor.json
new file mode 100644 (file)
index 0000000..a74da03
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "192.168.201.2":{
+    "remoteAs":65200,
+    "bgpTimerDelayOpenTimeMsecs":60000
+  }
+}
diff --git a/tests/topotests/bgp_features/r2/bgp_delayopen_summary_connect.json b/tests/topotests/bgp_features/r2/bgp_delayopen_summary_connect.json
new file mode 100644 (file)
index 0000000..c2b42ec
--- /dev/null
@@ -0,0 +1,11 @@
+{
+"ipv4Unicast":{
+  "as":65000,
+  "peers":{
+    "192.168.201.2":{
+      "remoteAs":65200,
+      "state":"Connect"
+    }
+  }
+}
+}
diff --git a/tests/topotests/bgp_features/r2/bgp_delayopen_summary_established.json b/tests/topotests/bgp_features/r2/bgp_delayopen_summary_established.json
new file mode 100644 (file)
index 0000000..77b6944
--- /dev/null
@@ -0,0 +1,11 @@
+{
+"ipv4Unicast":{
+  "as":65000,
+  "peers":{
+    "192.168.201.2":{
+      "remoteAs":65200,
+      "state":"Established"
+    }
+  }
+}
+}
diff --git a/tests/topotests/bgp_features/r2/bgp_delayopen_summary_shutdown.json b/tests/topotests/bgp_features/r2/bgp_delayopen_summary_shutdown.json
new file mode 100644 (file)
index 0000000..8f9476a
--- /dev/null
@@ -0,0 +1,11 @@
+{
+"ipv4Unicast":{
+  "as":65000,
+  "peers":{
+    "192.168.201.2":{
+      "remoteAs":65200,
+      "state":"Idle (Admin)"
+    }
+  }
+}
+}
index 283d20548913cade7dfcbf210b093a8db68a17e5..47bd5a99cc266c05751d4ec8d3810527ed764acf 100644 (file)
@@ -4,17 +4,16 @@ debug ospf6 neighbor
 !
 interface r2-lo
 !
-interface r2-eth0
-!
 interface r2-eth1
+ ipv6 ospf6 priority 5
 !
 interface r2-eth2
+ ipv6 ospf6 priority 10
 !
 router ospf6
  ospf6 router-id 192.168.0.2
  log-adjacency-changes
  interface r2-lo area 0.0.0.0
- interface r2-eth0 area 0.0.0.0
  interface r2-eth1 area 0.0.0.0
  interface r2-eth2 area 0.0.0.0
 !
index 5fcbd82ee1707fcba571036f26269524b43957cb..2fd589ae25d63d2f6de2dc60554e05cfa51530ea 100644 (file)
@@ -2,14 +2,14 @@
   "neighbors":{
     "192.168.0.1":[
       {
-        "priority":1,
-        "state":"Full\/Backup"
+        "priority":10,
+        "state":"Full\/DR"
       }
     ],
     "192.168.0.3":[
       {
-        "priority":1,
-        "state":"Full\/DR"
+        "priority":5,
+        "state":"Full\/Backup"
       }
     ]
   }
index 2174fddb11567c10037ac614c28bbf95ad9d7f0a..6f608e454bdb9546ef8cf1698ee9a425133b1668 100644 (file)
@@ -3,6 +3,16 @@ log file ospfd.log
 debug ospf event
 debug ospf zebra
 !
+int r2-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+ ip ospf priority 5
+!
+int r2-eth2
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+ ip ospf priority 10
+!
 router ospf
  ospf router-id 192.168.0.2
  log-adjacency-changes
@@ -12,12 +22,5 @@ router ospf
  timers throttle lsa all 0
  refresh timer 10
 !
-int r2-eth1
- ip ospf hello-interval 2
- ip ospf dead-interval 10
-int r2-eth2
- ip ospf hello-interval 2
- ip ospf dead-interval 10
-!
 line vty
 !
index 7a6623f9794ed4a7be22f77b02da8a51cbd7e3c1..eb74901ba1fdd434b60caff2cf9bd776db7b4ee3 100644 (file)
@@ -4,17 +4,16 @@ debug ospf6 neighbor
 !
 interface r3-lo
 !
-interface r3-eth0
-!
 interface r3-eth1
+ ipv6 ospf6 priority 5
 !
 interface r3-eth2
+ ipv6 ospf6 priority 5
 !
 router ospf6
  ospf6 router-id 192.168.0.3
  log-adjacency-changes
  interface r3-lo area 0.0.0.0
- interface r3-eth0 area 0.0.0.0
  interface r3-eth1 area 0.0.0.0
  interface r3-eth2 area 0.0.0.0
 !
index e90a70a8f6fa6e83a780c955832f9fedca2fdc49..80fc92c3bcd3f526a2f1c530e902098b6bfcf753 100644 (file)
@@ -2,14 +2,14 @@
   "neighbors":{
     "192.168.0.1":[
       {
-        "priority":1,
-        "state":"Full\/Backup"
+        "priority":10,
+        "state":"Full\/DR"
       }
     ],
     "192.168.0.2":[
       {
-        "priority":1,
-        "state":"Full\/Backup"
+        "priority":10,
+        "state":"Full\/DR"
       }
     ]
   }
index 795344fbe66d064967633e4beb1cbfdf15961a23..71e4f1e1dfc260ccc2ce82da400ef85aa8c750be 100644 (file)
@@ -3,6 +3,16 @@ log file ospfd.log
 debug ospf event
 debug ospf zebra
 !
+int r3-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+ ip ospf priority 5
+!
+int r3-eth2
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+ ip ospf priority 5
+!
 router ospf
  ospf router-id 192.168.0.3
  log-adjacency-changes
@@ -12,12 +22,5 @@ router ospf
  timers throttle lsa all 0
  refresh timer 10
 !
-int r3-eth1
-  ip ospf hello-interval 2
-  ip ospf dead-interval 10
-int r3-eth2
-  ip ospf hello-interval 2
-  ip ospf dead-interval 10
-!
 line vty
 !
diff --git a/tests/topotests/bgp_features/r4/bgp_delayopen_summary_established.json b/tests/topotests/bgp_features/r4/bgp_delayopen_summary_established.json
new file mode 100644 (file)
index 0000000..85caf55
--- /dev/null
@@ -0,0 +1,11 @@
+{
+"ipv4Unicast":{
+  "as":65100,
+  "peers":{
+    "192.168.101.1":{
+      "remoteAs":65000,
+      "state":"Established"
+    }
+  }
+}
+}
diff --git a/tests/topotests/bgp_features/r4/bgp_delayopen_summary_shutdown.json b/tests/topotests/bgp_features/r4/bgp_delayopen_summary_shutdown.json
new file mode 100644 (file)
index 0000000..cf784d8
--- /dev/null
@@ -0,0 +1,11 @@
+{
+"ipv4Unicast":{
+  "as":65100,
+  "peers":{
+    "192.168.101.1":{
+      "remoteAs":65000,
+      "state":"Idle (Admin)"
+    }
+  }
+}
+}
diff --git a/tests/topotests/bgp_features/r5/bgp_delayopen_neighbor.json b/tests/topotests/bgp_features/r5/bgp_delayopen_neighbor.json
new file mode 100644 (file)
index 0000000..4b97254
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "192.168.201.1":{
+    "remoteAs":65000,
+    "bgpTimerDelayOpenTimeMsecs":30000
+  }
+}
diff --git a/tests/topotests/bgp_features/r5/bgp_delayopen_summary_connect.json b/tests/topotests/bgp_features/r5/bgp_delayopen_summary_connect.json
new file mode 100644 (file)
index 0000000..d7b4e77
--- /dev/null
@@ -0,0 +1,11 @@
+{
+"ipv4Unicast":{
+  "as":65200,
+  "peers":{
+    "192.168.201.1":{
+      "remoteAs":65000,
+      "state":"Connect"
+    }
+  }
+}
+}
diff --git a/tests/topotests/bgp_features/r5/bgp_delayopen_summary_established.json b/tests/topotests/bgp_features/r5/bgp_delayopen_summary_established.json
new file mode 100644 (file)
index 0000000..15cfb19
--- /dev/null
@@ -0,0 +1,11 @@
+{
+"ipv4Unicast":{
+  "as":65200,
+  "peers":{
+    "192.168.201.1":{
+      "remoteAs":65000,
+      "state":"Established"
+    }
+  }
+}
+}
diff --git a/tests/topotests/bgp_features/r5/bgp_delayopen_summary_shutdown.json b/tests/topotests/bgp_features/r5/bgp_delayopen_summary_shutdown.json
new file mode 100644 (file)
index 0000000..94aceba
--- /dev/null
@@ -0,0 +1,11 @@
+{
+"ipv4Unicast":{
+  "as":65200,
+  "peers":{
+    "192.168.201.1":{
+      "remoteAs":65000,
+      "state":"Idle (Admin)"
+    }
+  }
+}
+}
index bd092c4340f97e723662903ebcd8554787668bf2..3d963b4cf65b53291454de680025110d37659f70 100644 (file)
@@ -32,6 +32,8 @@ import os
 import sys
 import pytest
 import re
+import time
+from time import sleep
 
 # Save the Current Working Directory to find configuration files.
 CWD = os.path.dirname(os.path.realpath(__file__))
@@ -63,6 +65,14 @@ class BGPFeaturesTopo1(Topo):
         for rtrNum in range(1, 6):
             tgen.add_router("r{}".format(rtrNum))
 
+        # create ExaBGP peers
+        for peer_num in range(1, 5):
+            tgen.add_exabgp_peer(
+                "peer{}".format(peer_num),
+                ip="192.168.101.{}".format(peer_num + 2),
+                defaultRoute="via 192.168.101.1",
+            )
+
         # Setup Switches and connections
         for swNum in range(1, 11):
             tgen.add_switch("sw{}".format(swNum))
@@ -88,6 +98,12 @@ class BGPFeaturesTopo1(Topo):
         tgen.gears["r2"].add_link(tgen.gears["sw5"])
         tgen.gears["r5"].add_link(tgen.gears["sw5"])
 
+        # Add ExaBGP peers to sw4
+        tgen.gears["peer1"].add_link(tgen.gears["sw4"])
+        tgen.gears["peer2"].add_link(tgen.gears["sw4"])
+        tgen.gears["peer3"].add_link(tgen.gears["sw4"])
+        tgen.gears["peer4"].add_link(tgen.gears["sw4"])
+
 
 #####################################################
 #
@@ -102,7 +118,7 @@ def setup_module(module):
 
     # Starting Routers
     router_list = tgen.routers()
-    for rname, router in router_list.iteritems():
+    for rname, router in router_list.items():
         router.load_config(
             TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
         )
@@ -745,6 +761,1009 @@ def test_bgp_disable_norib_routes():
     # tgen.mininet_cli()
 
 
+def test_bgp_delayopen_without():
+    "Optional test of BGP functionality and behaviour without DelayOpenTimer enabled to establish a reference for following tests"
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # part 1: no delay r1 <=> no delay r4
+    logger.info(
+        "Starting optional test of BGP functionality without DelayOpenTimer enabled to establish a reference for following tests"
+    )
+
+    # 1.1 enable peering shutdown
+    logger.info("Enable shutdown of peering between r1 and r4")
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 shutdown"'
+    )
+    tgen.net["r4"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65100" -c "neighbor 192.168.101.1 shutdown"'
+    )
+
+    # 1.2 wait for peers to shut down (poll output)
+    for router_num in [1, 4]:
+        logger.info(
+            "Checking BGP summary after enabling shutdown of peering on r{}".format(
+                router_num
+            )
+        )
+        router = tgen.gears["r{}".format(router_num)]
+        reffile = os.path.join(
+            CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num)
+        )
+        expected = json.loads(open(reffile).read())
+        test_func = functools.partial(
+            topotest.router_json_cmp, router, "show ip bgp summary json", expected
+        )
+        _, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
+        assertmsg = "BGP session on r{} did not shut down peer".format(router_num)
+        assert res is None, assertmsg
+
+    # 1.3 disable peering shutdown
+    logger.info("Disable shutdown of peering between r1 and r4")
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 shutdown"'
+    )
+    tgen.net["r4"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65100" -c "no neighbor 192.168.101.1 shutdown"'
+    )
+
+    # 1.4 wait for peers to establish connection (poll output)
+    for router_num in [1, 4]:
+        logger.info(
+            "Checking BGP summary after disabling shutdown of peering on r{}".format(
+                router_num
+            )
+        )
+        router = tgen.gears["r{}".format(router_num)]
+        reffile = os.path.join(
+            CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num)
+        )
+        expected = json.loads(open(reffile).read())
+        test_func = functools.partial(
+            topotest.router_json_cmp, router, "show ip bgp summary json", expected
+        )
+        _, res = topotest.run_and_expect(test_func, None, count=5, wait=1)
+        assertmsg = (
+            "BGP session on r{} did not establish a connection with peer".format(
+                router_num
+            )
+        )
+        assert res is None, assertmsg
+
+    # tgen.mininet_cli()
+
+    # end test_bgp_delayopen_without
+
+
+def test_bgp_delayopen_singular():
+    "Test of BGP functionality and behaviour with DelayOpenTimer enabled on one side of the peering"
+
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # part 2: delay 240s r1 <=> no delay r4
+    logger.info(
+        "Starting test of BGP functionality and behaviour with DelayOpenTimer enabled on one side of the peering"
+    )
+
+    # 2.1 enable peering shutdown
+    logger.info("Enable shutdown of peering between r1 and r4")
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 shutdown"'
+    )
+    tgen.net["r4"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65100" -c "neighbor 192.168.101.1 shutdown"'
+    )
+
+    # 2.2 wait for peers to shut down (poll output)
+    for router_num in [1, 4]:
+        logger.info(
+            "Checking BGP summary after disabling shutdown of peering on r{}".format(
+                router_num
+            )
+        )
+        router = tgen.gears["r{}".format(router_num)]
+        reffile = os.path.join(
+            CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num)
+        )
+        expected = json.loads(open(reffile).read())
+        test_func = functools.partial(
+            topotest.router_json_cmp, router, "show ip bgp summary json", expected
+        )
+        _, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
+        assertmsg = "BGP session on r{} did not shut down peer".format(router_num)
+        assert res is None, assertmsg
+
+    # 2.3 set delayopen on R1 to 240
+    logger.info("Setting DelayOpenTime for neighbor r4 to 240 seconds on r1")
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 timers delayopen 240"'
+    )
+
+    # 2.4 check config (poll output)
+    logger.info("Checking BGP neighbor configuration after setting DelayOpenTime on r1")
+    router = tgen.gears["r1"]
+    reffile = os.path.join(CWD, "r1/bgp_delayopen_neighbor.json")
+    expected = json.loads(open(reffile).read())
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show bgp neighbors json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
+    assertmsg = "BGP session on r1 failed to set DelayOpenTime for r4"
+    assert res is None, assertmsg
+
+    # 2.5 disable peering shutdown
+    logger.info("Disable shutdown of peering between r1 and r4")
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 shutdown"'
+    )
+    tgen.net["r4"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65100" -c "no neighbor 192.168.101.1 shutdown"'
+    )
+
+    # 2.6 wait for peers to establish connection (poll output)
+    for router_num in [1, 4]:
+        logger.info(
+            "Checking BGP summary after disabling shutdown of peering on r{}".format(
+                router_num
+            )
+        )
+        router = tgen.gears["r{}".format(router_num)]
+        reffile = os.path.join(
+            CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num)
+        )
+        expected = json.loads(open(reffile).read())
+        test_func = functools.partial(
+            topotest.router_json_cmp, router, "show ip bgp summary json", expected
+        )
+        _, res = topotest.run_and_expect(test_func, None, count=5, wait=1)
+        assertmsg = (
+            "BGP session on r{} did not establish a connection with peer".format(
+                router_num
+            )
+        )
+        assert res is None, assertmsg
+
+    # 2.7 unset delayopen on R1
+    logger.info("Disabling DelayOpenTimer for neighbor r4 on r1")
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 timers delayopen"'
+    )
+
+    # 2.8 check config (poll output)
+    logger.info(
+        "Checking BGP neighbor configuration after disabling DelayOpenTimer on r1"
+    )
+    delayopen_cfg = (
+        tgen.net["r1"]
+        .cmd('vtysh -c "show bgp neighbors json" | grep "DelayOpenTimeMsecs"')
+        .rstrip()
+    )
+    assertmsg = "BGP session on r1 failed disable DelayOpenTimer for peer r4"
+    assert delayopen_cfg == "", assertmsg
+
+    # tgen.mininet_cli()
+
+    # end test_bgp_delayopen_singular
+
+
+def test_bgp_delayopen_dual():
+    "Test of BGP functionality and behaviour with DelayOpenTimer enabled on both sides of the peering with different timer intervals"
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # part 3: delay 60s R2 <=> delay 30s R5
+    logger.info(
+        "Starting test of BGP functionality and behaviour with DelayOpenTimer enabled on both sides of the peering with different timer intervals"
+    )
+
+    # 3.1 enable peering shutdown
+    logger.info("Enable shutdown of peering between r2 and r5")
+    tgen.net["r2"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.201.2 shutdown"'
+    )
+    tgen.net["r5"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65200" -c "neighbor 192.168.201.1 shutdown"'
+    )
+
+    # 3.2 wait for peers to shut down (pool output)
+    for router_num in [2, 5]:
+        logger.info(
+            "Checking BGP summary after disabling shutdown of peering on r{}".format(
+                router_num
+            )
+        )
+        router = tgen.gears["r{}".format(router_num)]
+        reffile = os.path.join(
+            CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num)
+        )
+        expected = json.loads(open(reffile).read())
+        test_func = functools.partial(
+            topotest.router_json_cmp, router, "show ip bgp summary json", expected
+        )
+        _, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
+        assertmsg = "BGP session on r{} did not shut down peer".format(router_num)
+        assert res is None, assertmsg
+
+    # 3.3 set delayopen on R2 to 60s and on R5 to 30s
+    logger.info("Setting DelayOpenTime for neighbor r5 to 60 seconds on r2")
+    tgen.net["r2"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.201.2 timers delayopen 60"'
+    )
+    logger.info("Setting DelayOpenTime for neighbor r2 to 30 seconds on r5")
+    tgen.net["r5"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65200" -c "neighbor 192.168.201.1 timers delayopen 30"'
+    )
+
+    # 3.4 check config (poll output)
+    for router_num in [2, 5]:
+        logger.info(
+            "Checking BGP neighbor configuration after setting DelayOpenTime on r{}i".format(
+                router_num
+            )
+        )
+        router = tgen.gears["r{}".format(router_num)]
+        reffile = os.path.join(
+            CWD, "r{}/bgp_delayopen_neighbor.json".format(router_num)
+        )
+        expected = json.loads(open(reffile).read())
+        test_func = functools.partial(
+            topotest.router_json_cmp, router, "show bgp neighbors json", expected
+        )
+        _, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
+        assertmsg = "BGP session on r{} failed to set DelayOpenTime".format(router_num)
+        assert res is None, assertmsg
+
+    ## 3.5 disable peering shutdown
+    logger.info("Disable shutdown of peering between r2 and r5")
+    tgen.net["r2"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.201.2 shutdown"'
+    )
+    tgen.net["r5"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65200" -c "no neighbor 192.168.201.1 shutdown"'
+    )
+
+    ## 3.6 wait for peers to reach connect or active state (poll output)
+    delay_start = int(time.time())
+    for router_num in [2, 5]:
+        logger.info(
+            "Checking BGP summary after disabling shutdown of peering on r{}".format(
+                router_num
+            )
+        )
+        router = tgen.gears["r{}".format(router_num)]
+        reffile = os.path.join(
+            CWD, "r{}/bgp_delayopen_summary_connect.json".format(router_num)
+        )
+        expected = json.loads(open(reffile).read())
+        test_func = functools.partial(
+            topotest.router_json_cmp, router, "show ip bgp summary json", expected
+        )
+        _, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
+        assertmsg = "BGP session on r{} did not enter Connect state with peer".format(
+            router_num
+        )
+        assert res is None, assertmsg
+
+    ## 3.7 wait for peers to establish connection (poll output)
+    for router_num in [2, 5]:
+        logger.info(
+            "Checking BGP summary after disabling shutdown of peering on r{}".format(
+                router_num
+            )
+        )
+        router = tgen.gears["r{}".format(router_num)]
+        reffile = os.path.join(
+            CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num)
+        )
+        expected = json.loads(open(reffile).read())
+        test_func = functools.partial(
+            topotest.router_json_cmp, router, "show ip bgp summary json", expected
+        )
+        _, res = topotest.run_and_expect(test_func, None, count=35, wait=1)
+        assertmsg = (
+            "BGP session on r{} did not establish a connection with peer".format(
+                router_num
+            )
+        )
+        assert res is None, assertmsg
+
+    delay_stop = int(time.time())
+    assertmsg = "BGP peering between r2 and r5 was established before DelayOpenTimer (30sec) on r2 could expire"
+    assert (delay_stop - delay_start) > 30, assertmsg
+
+    # 3.8 unset delayopen on R2 and R5
+    logger.info("Disabling DelayOpenTimer for neighbor r5 on r2")
+    tgen.net["r2"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.201.2 timers delayopen"'
+    )
+    logger.info("Disabling DelayOpenTimer for neighbor r2 on r5")
+    tgen.net["r5"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65200" -c "no neighbor 192.168.201.1 timers delayopen"'
+    )
+
+    # 3.9 check config (poll output)
+    for router_num in [2, 5]:
+        logger.info(
+            "Checking BGP neighbor configuration after disabling DelayOpenTimer on r{}".format(
+                router_num
+            )
+        )
+        delayopen_cfg = (
+            tgen.net["r{}".format(router_num)]
+            .cmd('vtysh -c "show bgp neighbors json" | grep "DelayOpenTimeMsecs"')
+            .rstrip()
+        )
+        assertmsg = "BGP session on r{} failed disable DelayOpenTimer".format(
+            router_num
+        )
+        assert delayopen_cfg == "", assertmsg
+
+    # tgen.mininet_cli()
+
+    # end test_bgp_delayopen_dual
+
+
+def test_bgp_dampening_setup():
+    "BGP route-flap dampening test setup"
+
+    # This test starts four ExaBGP peers, adds them as neighbors to the
+    # configuration of router r1 and checks if connections get established.
+
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Starting BGP route-flap dampening test setup")
+
+    # Start ExaBGP peers connected to r1 via switch 4
+    logger.info("Starting ExaBGP peers")
+    for peer_num in range(1, 5):
+        logger.info("Creating named pipe for ExaBGP peer peer{}".format(peer_num))
+        fifo_in = "/var/run/exabgp_peer{}.in".format(peer_num)
+        if os.path.exists(fifo_in):
+            os.remove(fifo_in)
+        os.mkfifo(fifo_in, 0o777)
+        logger.info("Starting ExaBGP on peer peer{}".format(peer_num))
+        peer = tgen.gears["peer{}".format(peer_num)]
+        peer_dir = os.path.join(CWD, "peer{}".format(peer_num))
+        env_file = os.path.join(CWD, "exabgp.env")
+        peer.start(peer_dir, env_file)
+
+    # Add ExaBGP peers to configuration of router r2
+    logger.info("Adding ExaBGP peers as neighbors to configuration of router r2")
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.3 remote-as 65403"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.3 route-map testmap-in"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.3 route-map testmap-out"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.4 remote-as 65404"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.4 route-map testmap-in"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.4 route-map testmap-out"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.5 remote-as 65405"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.5 route-map testmap-in"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.5 route-map testmap-out"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.6 remote-as 65406"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.6 route-map testmap-in"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.6 route-map testmap-out"'
+    )
+
+    # Check if exabgp peers are up and running
+    logger.info("Checking for established connections to ExaBGP peers on router r1")
+    router = tgen.gears["r1"]
+    reffile = os.path.join(CWD, "r1/bgp_damp_setup.json")
+    expected = json.loads(open(reffile).read())
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show ip bgp summary json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
+    assertmsg = (
+        "BGP session on r1 did not establish connections with one ore more ExaBGP peers"
+    )
+    assert res is None, assertmsg
+
+    # end test_bgp_dampening_setup
+
+
+def test_bgp_dampening_route_announce():
+    "Test of BGP route-flap dampening route announcement"
+
+    # This test checks if the four ExaBGP peers can announce routes to router
+    # r1 and if these routes get forwarded to router r2.
+
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Starting test of BGP route-flap dampening route announcement")
+
+    # Announce routes on exabgp peers to r2
+    logger.info("Announcing routes on ExaBGP peers to r1")
+    for prefix_iter in range(1, 5):
+        for peer_num in range(1, 5):
+            pipe = open("/run/exabgp_peer{}.in".format(peer_num), "w")
+            with pipe:
+                pipe.write(
+                    "announce route 192.168.{}{}.0/24 next-hop 192.168.101.{}\n".format(
+                        (peer_num + 2), prefix_iter, (peer_num + 2)
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+
+    # Check if routes announced by ExaBGP peers are present in RIB of router r1
+    logger.info(
+        "Checking if routes announced by ExaBGP peers are present in RIB of router r1"
+    )
+    router = tgen.gears["r1"]
+    reffile = os.path.join(CWD, "r1/bgp_damp_announced.json")
+    expected = json.loads(open(reffile).read())
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show ip bgp json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
+    assertmsg = (
+        "BGP session on router r1 did not receive routes announced by ExaBGP peers"
+    )
+    assert res is None, assertmsg
+
+    # Check if routes announced by ExaBGP peers to router r1 have been forwarded
+    # and are now present in RIB of router r2
+    logger.info(
+        "Checking if forwarded routes announced by ExaBGP peers are present in RIB of router r2"
+    )
+    router = tgen.gears["r2"]
+    reffile = os.path.join(CWD, "r2/bgp_damp_announced.json")
+    expected = json.loads(open(reffile).read())
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show ip bgp json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
+    assertmsg = "BGP session on router r2 did not receive routes announced by ExaBGP peers forwarded by router r1"
+    assert res is None, assertmsg
+
+    # end test_bgp_dampening_route_announce
+
+
+def test_bgp_dampening_disabled():
+    "Test of BGP route-flapping with dampening disabled"
+
+    # This test verifies that flapped routes do not get withdrawn from the RIB
+    # of router r1 if dampening is disabled.
+
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Starting test of BGP route-flapping with dampening disabled")
+
+    # Flapping routes on ExaBGP peer peer1
+    logger.info(
+        "Flapping routes on ExaBGP peer peer1 with route-flap dampening disabled"
+    )
+    for _ in range(1, 5):
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer1.in", "w")
+            with pipe:
+                pipe.write(
+                    "withdraw route 192.168.3{}.0/24 next-hop 192.168.101.3\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+        sleep(1)  # Give the BGP session on router r1 time to process routes
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer1.in", "w")
+            with pipe:
+                pipe.write(
+                    "announce route 192.168.3{}.0/24 next-hop 192.168.101.3\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+
+    # Verify flapped routes are still present in RIB of router r1
+    logger.info(
+        "Verifying that the flapped routes are still present in RIB of router r1"
+    )
+    router = tgen.gears["r1"]
+    reffile = os.path.join(CWD, "r1/bgp_damp_announced.json")
+    expected = json.loads(open(reffile).read())
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show ip bgp json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
+    assertmsg = "BGP session on router r1 removed flapped routes despite route-flap dampening being disabled"
+    assert res is None, assertmsg
+
+    # end test_bgp_dampening_disabled
+
+
+def test_bgp_dampening_config():
+    "Test of BGP route-flap dampening configuration"
+
+    # This test adds peer-group group1 with peers peer1 and peer2 to the
+    # configuration of router r1, sets up dampening configurations with
+    # different profiles and verifies the configured dampening parameters.
+
+    tgen = get_topogen()
+    r_1 = tgen.net["r1"]
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Starting test of BGP route-flap dampening configuration")
+
+    # Add peer-group group1 with peers peer1 and peer2
+    logger.info(
+        "Creating peer-group group1 and adding ExaBGP peers peer1 and peer2 to it"
+    )
+    r_1.cmd('vtysh -c "conf t" -c "router bgp 65000" -c "neighbor group1 peer-group"')
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.3 peer-group group1"'
+    )  # peer1
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.4 peer-group group1"'
+    )  # peer2
+
+    # Enable different dampening profiles for peer1, peer3, group1 and global
+    # configuration
+    logger.info(
+        "Enabling different dampening profiles for peer1, peer3, group1 and global configuration"
+    )
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "bgp dampening 30 300 900 90"'
+    )
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor group1 dampening 20 200 600 60"'
+    )
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.3 dampening 10 100 300 30"'
+    )  # peer1
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.5 dampening 10 100 300 30"'
+    )  # peer3
+
+    # Verify route-flap dampening configuration
+    logger.info("Verifying route-flap dampening configuration on router r1")
+    vtyout = r_1.cmd('vtysh -c "show running-config"')
+    assertmsg = "BGP Session on r1 does not show enabled global route-flap dampening in running configuration"
+    assert re.search("bgp dampening 30 300 900 90", vtyout), assertmsg
+    assertmsg = "BGP Session on r1 does not show route-flap dampening enabled for peer-group group1 in running configuration"
+    assert re.search("neighbor group1 dampening 20 200 600 60", vtyout), assertmsg
+    assertmsg = "BGP Session on r1 does not show route-flap dampening enabled for peer peer1 in running configuration"
+    assert re.search(
+        "neighbor 192.168.101.3 dampening 10 100 300 30", vtyout
+    ), assertmsg
+    assertmsg = "BGP Session on r1 does not show route-flap dampening enabled for peer peer3 in running configuration"
+    assert re.search(
+        "neighbor 192.168.101.5 dampening 10 100 300 30", vtyout
+    ), assertmsg
+
+    # end test_bgp_dampening_config
+
+
+def test_bgp_dampening_profile_peer_over_group():
+    "Test of BGP route-flap dampening profile preferences: peer over group"
+
+    # This test verifies that the dampening profile of a peer takes precedence
+    # over the dampening profile of its peer-group by flapping the peers routes
+    # until dampened and comparing the reuse times to the one specified in the
+    # dampening configuration.
+
+    tgen = get_topogen()
+    r_1 = tgen.net["r1"]
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info(
+        "Starting test of BGP route-flap dampening profile preferences: peer over group"
+    )
+
+    # Flapping routes on ExaBGP peer peer1
+    logger.info(
+        "Flapping routes on ExaBGP peer peer1 with route-flap dampening enabled"
+    )
+    for _ in range(1, 5):
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer1.in", "w")
+            with pipe:
+                pipe.write(
+                    "withdraw route 192.168.3{}.0/24 next-hop 192.168.101.3\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+        sleep(1)  # Give the BGP session on router r1 time to process routes
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer1.in", "w")
+            with pipe:
+                pipe.write(
+                    "announce route 192.168.3{}.0/24 next-hop 192.168.101.3\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+
+    # Check damped paths on r1 for routes of peer1 witn peer profile
+    logger.info(
+        "Checking if router r1 used the correct dampening profile on routes flapped by ExaBGP peer peer1"
+    )
+    sleep(5)  # Wait 5 seconds for paths to show up in dampened-paths list
+    vtyout = r_1.cmd('vtysh -c "show ip bgp dampening dampened-paths"')
+    routes = re.findall(r"\*d 192\.168\.3\d\.0\/24.*", vtyout)
+    assertmsg = (
+        "BGP session on router r1 did not dampen routes flapped by ExaBGP peer peer1"
+    )
+    assert len(routes) == 4, assertmsg
+    assertmsg = "BGP session on router r1 used wrong dampening profile for a route flapped by ExaBGP peer peer1"
+    for route in routes:
+        assert (int(route.split()[3].split(":")[0]) == 0) and (  # hours of reuse time
+            35 > int(route.split()[3].split(":")[1]) > 25
+        ), assertmsg  # minutes of reuse time
+
+    # end test_bgp_dampening_profile_peer_over_group
+
+
+def test_bgp_dampening_profile_group_over_global():
+    "Test of BGP route-flap dampening profile preferences: group over global"
+
+    # This test verifies that the dampening profile of a peer-group takes
+    # precedence over the global dampening profile by flapping the routes of a
+    # peer-group member until dampened and comparing the reuse times to the one
+    # specified in the dampening configuration.
+
+    tgen = get_topogen()
+    r_1 = tgen.net["r1"]
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info(
+        "Starting test of BGP route-flap dampening profile preferences: group over global"
+    )
+
+    # Flapping routes on ExaBGP peer peer2
+    logger.info(
+        "Flapping routes on ExaBGP peer peer2 with route-flap dampening enabled"
+    )
+    for _ in range(1, 5):
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer2.in", "w")
+            with pipe:
+                pipe.write(
+                    "withdraw route 192.168.4{}.0/24 next-hop 192.168.101.4\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+        sleep(1)  # Give the BGP session on router r1 time to process routes
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer2.in", "w")
+            with pipe:
+                pipe.write(
+                    "announce route 192.168.4{}.0/24 next-hop 192.168.101.4\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+
+    # Check damped paths on r1 for routes of peer2 witn group profile
+    logger.info(
+        "Checking if router r1 used the correct dampening profile on routes flapped by ExaBGP peer peer2"
+    )
+    sleep(5)  # wait 5 seconds for paths to shop up in damp list
+    vtyout = r_1.cmd('vtysh -c "show ip bgp dampening dampened-paths"')
+    routes = re.findall(r"\*d 192\.168\.4\d\.0\/24.*", vtyout)
+    assertmsg = (
+        "BGP session on router r1 did not dampen routes flapped by ExaBGP peer peer2"
+    )
+    assert len(routes) == 4, assertmsg
+    assertmsg = "BGP session on router r1 used wrong dampening profile for a route flapped by ExaBGP peer peer2"
+    for route in routes:
+        assert (int(route.split()[3].split(":")[0]) == 0) and (  # hours of reuse time
+            65 > int(route.split()[3].split(":")[1]) > 55
+        ), assertmsg  # minutes of reuse time
+
+    # end test_bgp_dampening_profile_group_over_global
+
+
+def test_bgp_dampening_profile_peer_over_global():
+    "Test of BGP route-flap dampening profile preferences: peer over global"
+
+    # This test verifies that the dampening profile of a peer takes precedence
+    # over the global dampening profile by flapping the routes of the peer until
+    # dampened and comparing the reuse times to the one specified in the
+    # dampening configuration.
+
+    tgen = get_topogen()
+    r_1 = tgen.net["r1"]
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info(
+        "Starting test of BGP route-flap dampening profile preferences: peer over global"
+    )
+
+    # Flapping routes on ExaBGP peer peer3
+    logger.info(
+        "Flapping routes on ExaBGP peer peer3 with route-flap dampening enabled"
+    )
+    for _ in range(1, 5):
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer3.in", "w")
+            with pipe:
+                pipe.write(
+                    "withdraw route 192.168.5{}.0/24 next-hop 192.168.101.5\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+        sleep(1)  # Give the BGP session on router r1 time to process routes
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer3.in", "w")
+            with pipe:
+                pipe.write(
+                    "announce route 192.168.5{}.0/24 next-hop 192.168.101.5\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+
+    # Check damped paths on r1 for routes of peer3 witn peer profile
+    logger.info(
+        "Checking if router r1 used the correct dampening profile on routes flapped by ExaBGP peer peer3"
+    )
+    sleep(5)  # wait 5 seconds for paths to shop up in damp list
+    vtyout = r_1.cmd('vtysh -c "show ip bgp dampening dampened-paths"')
+    routes = re.findall(r"\*d 192\.168\.5\d\.0\/24.*", vtyout)
+    assertmsg = (
+        "BGP session on router r1 did not dampen routes flapped by ExaBGP peer peer3"
+    )
+    assert len(routes) == 4, assertmsg
+    assertmsg = "BGP session on router r1 used wrong dampening profile for a route flapped by ExaBGP peer peer3"
+    for route in routes:
+        assert (int(route.split()[3].split(":")[0]) == 0) and (  # hours of reuse time
+            35 > int(route.split()[3].split(":")[1]) > 25
+        ), assertmsg  # minutes of reuse time
+
+    # end test_bgp_dampening_profile_peer_over_global
+
+
+def test_bgp_dampening_profile_global():
+    "Test of BGP route-flap dampening global profile"
+
+    # This test verifies the application of the global dampening profile by
+    # flapping the routes of a peer until dampened and comparing the reuse times
+    # to the one specified in the dampening configuration.
+
+    tgen = get_topogen()
+    r_1 = tgen.net["r1"]
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Starting test of BGP route-flap dampening global profile")
+
+    # Flapping routes on ExaBGP peer peer4
+    logger.info(
+        "Flapping routes on ExaBGP peer peer4 with route-flap dampening enabled"
+    )
+    for _ in range(1, 5):
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer4.in", "w")
+            with pipe:
+                pipe.write(
+                    "withdraw route 192.168.6{}.0/24 next-hop 192.168.101.6\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+        sleep(1)  # Give the BGP session on router r1 time to process routes
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer4.in", "w")
+            with pipe:
+                pipe.write(
+                    "announce route 192.168.6{}.0/24 next-hop 192.168.101.6\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+
+    # Check damped paths on r1 for routes of peer4 witn global profile
+    logger.info(
+        "Checking if router r1 used the global dampening profile on routes flapped by ExaBGP peer peer4"
+    )
+    sleep(5)  # wait 5 seconds for paths to shop up in damp list
+    vtyout = r_1.cmd('vtysh -c "show ip bgp dampening dampened-paths"')
+    routes = re.findall(r"\*d 192\.168\.6\d\.0\/24.*", vtyout)
+    assertmsg = (
+        "BGP session on router r1 did not dampen routes flapped by ExaBGP peer peer4"
+    )
+    assert len(routes) == 4, assertmsg
+    assertmsg = "BGP session on router r1 did not use the global dampening profile for a route flapped by ExaBGP peer peer4"
+    for route in routes:
+        assert (int(route.split()[3].split(":")[0]) == 1) and (  # hours of reuse time
+            35 > int(route.split()[3].split(":")[1]) > 25
+        ), assertmsg  # minutes of reuse time
+
+    # end test_bgp_dampening_profile_global
+
+
+def test_bgp_dampening_withdaw():
+    "Test BGP route-flap dampening route withdraw"
+
+    # This test verifies that the withrawl of dampened routes from the RIB of
+    # router r1 was propagated to router r2.
+
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Starting test of BGP route-flap dampening route withdraw")
+
+    # Check if routes dampened on router r1 have been withdrawn from the RIB on
+    # router r2
+    logger.info(
+        "Checking if routes dampened on router r1 have been withdrawn of RIB on router r2"
+    )
+    reffile = os.path.join(CWD, "r2/bgp_damp_withdrawn.json")
+    expected = json.loads(open(reffile).read())
+    test_func = functools.partial(
+        topotest.router_json_cmp, tgen.gears["r2"], "show ip bgp json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=5, wait=1)
+    assertmsg = "BGP session on router r2 did not receive withdraw of routes dampened on router r1"
+    assert res is None, assertmsg
+
+    # end test_bgp_dampening_withdaw
+
+
+def test_bgp_dampening_cleanup():
+    "BGP route-flap dampening test cleanup"
+
+    # This test cleans up after other tests associated with route-flap dampening
+    # by disabling all dampening configurations, removing added peers and
+    # peer-groups from the configuration on router r1, and shutting down ExaBGP
+    # peers peer1, peer2 and peer3.
+
+    tgen = get_topogen()
+    r_1 = tgen.net["r1"]
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Starting BGP route-flap dampening test cleanup")
+
+    # Disable all dampening configurations
+    logger.info("Disabling all dampening configurations")
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "no bgp dampening"'
+    )
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "no neighbor group1 dampening"'
+    )
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "no neighbor 192.168.101.3 dampening"'
+    )
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "no neighbor 192.168.101.5 dampening"'
+    )
+
+    # Remove ExaBGP peers from configuration of router r1
+    logger.info("Removing ExaBGP peers from configuration of router r1")
+    for router_num in range(3, 7):
+        r_1.cmd(
+            'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.{}"'.format(
+                router_num
+            )
+        )
+
+    # Remove peer-group group1 from configuration of router r1
+    logger.info("Removing peer-group group1 peers from configuration of router r1")
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor group1 peer-group"'
+    )
+
+    # Stop ExaBGP peers and remove associated named pipes
+    logger.info("Stopping ExaBGP peers and removing associated named pipes")
+    for peer_num in range(1, 5):
+        logger.info("Terminating ExaBGP on peer peer{}".format(peer_num))
+        peer = tgen.gears["peer{}".format(peer_num)]
+        logger.info("Removing named pipe of ExaBGP peer peer{}".format(peer_num))
+        fifo_in = "/var/run/exabgp_peer{}.in".format(peer_num)
+        peer.stop()
+        if os.path.exists(fifo_in):
+            os.remove(fifo_in)
+
+    # end test_bgp_dampening_cleanup
+
+
+def test_bgp_dampening_aftermath():
+    "BGP route-flap dampening aftermath test"
+
+    # This test verifies routers r1 and r2 not being affected by the route-flap
+    # dampening test series.
+
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # Check BGP Summary on routers r1 and r2
+    for rtr_num in [1, 2]:
+        logger.info(
+            "Checking if BGP router on r{} remains unaffected by route-flap dampening tests".format(
+                rtr_num
+            )
+        )
+        router = tgen.gears["r{}".format(rtr_num)]
+        reffile = os.path.join(CWD, "r{}/show_bgp.json".format(rtr_num))
+        expected = json.loads(open(reffile).read())
+        test_func = functools.partial(
+            topotest.router_json_cmp, router, "show ip bgp json", expected
+        )
+        _, res = topotest.run_and_expect(test_func, None, count=10, wait=2)
+        assertmsg = "BGP routes on router r{} are wrong after route-flap dampening tests".format(
+            rtr_num
+        )
+        assert res is None, assertmsg
+
+    # end test_bgp_dampening_aftermath
+
+
 if __name__ == "__main__":
     args = ["-s"] + sys.argv[1:]
     sys.exit(pytest.main(args))
index 097b654e771269d2c852e94d31d2d5c7995649a6..3a2d2830257951ff4d81026fde21a014234bd6c7 100644 (file)
@@ -316,7 +316,9 @@ def test_BGP_GR_TC_46_p1(request):
     input_dict = {
         "r1": {
             "bgp": {
-                "graceful-restart": {"graceful-restart": True,},
+                "graceful-restart": {
+                    "graceful-restart": True,
+                },
                 "address_family": {
                     "ipv4": {
                         "unicast": {
@@ -1184,8 +1186,8 @@ def test_BGP_GR_TC_53_p1(request):
 
 def test_BGP_GR_TC_4_p0(request):
     """
-     Test Objective : Verify that the restarting node sets "R" bit while sending the
-     BGP open messages after the node restart, only if GR is enabled.
+    Test Objective : Verify that the restarting node sets "R" bit while sending the
+    BGP open messages after the node restart, only if GR is enabled.
     """
 
     tgen = get_topogen()
@@ -1368,9 +1370,9 @@ def test_BGP_GR_TC_4_p0(request):
 
 def test_BGP_GR_TC_5_1_2_p1(request):
     """
-     Test Objective : Verify if restarting node resets R bit in BGP open message
-     during normal BGP session flaps as well, even when GR restarting mode is enabled.
-     Here link flap happen due to interface UP/DOWN.
+    Test Objective : Verify if restarting node resets R bit in BGP open message
+    during normal BGP session flaps as well, even when GR restarting mode is enabled.
+    Here link flap happen due to interface UP/DOWN.
 
     """
     tgen = get_topogen()
@@ -1486,7 +1488,7 @@ def test_BGP_GR_TC_5_1_2_p1(request):
     shutdown_bringup_interface(tgen, "r2", intf)
 
     # Bring up Interface
-    shutdown_bringup_interface(tgen, dut, intf, ifaceaction=True)
+    shutdown_bringup_interface(tgen, "r2", intf, ifaceaction=True)
 
     for addr_type in ADDR_TYPES:
         result = verify_graceful_restart(
@@ -1773,7 +1775,7 @@ def test_BGP_GR_TC_6_1_2_p1(request):
     shutdown_bringup_interface(tgen, "r2", intf)
 
     # Bring up Interface
-    shutdown_bringup_interface(tgen, dut, intf, ifaceaction=True)
+    shutdown_bringup_interface(tgen, "r2", intf, ifaceaction=True)
 
     for addr_type in ADDR_TYPES:
         result = verify_graceful_restart(
@@ -1815,8 +1817,8 @@ def test_BGP_GR_TC_6_1_2_p1(request):
 
 def test_BGP_GR_TC_8_p1(request):
     """
-     Test Objective : Verify that restarting nodes set "F" bit while sending
-      the BGP open messages after it restarts, only when BGP GR is enabled.
+    Test Objective : Verify that restarting nodes set "F" bit while sending
+     the BGP open messages after it restarts, only when BGP GR is enabled.
     """
 
     tgen = get_topogen()
@@ -1959,8 +1961,8 @@ def test_BGP_GR_TC_8_p1(request):
 
 def test_BGP_GR_TC_17_p1(request):
     """
-      Test Objective : Verify that only GR helper routers keep the stale
-       route entries, not any GR disabled router.
+    Test Objective : Verify that only GR helper routers keep the stale
+     route entries, not any GR disabled router.
     """
 
     tgen = get_topogen()
@@ -2145,8 +2147,8 @@ def test_BGP_GR_TC_17_p1(request):
 
 def test_BGP_GR_TC_19_p1(request):
     """
-      Test Objective : Verify that GR helper routers keeps all the routes received
-      from restarting node if both the routers are configured as GR restarting node.
+    Test Objective : Verify that GR helper routers keeps all the routes received
+    from restarting node if both the routers are configured as GR restarting node.
     """
 
     tgen = get_topogen()
@@ -2325,8 +2327,8 @@ def test_BGP_GR_TC_19_p1(request):
 
 def test_BGP_GR_TC_20_p1(request):
     """
-      Test Objective : Verify that GR helper routers delete all the routes
-       received from a node if both the routers are configured as GR helper node.
+    Test Objective : Verify that GR helper routers delete all the routes
+     received from a node if both the routers are configured as GR helper node.
     """
     tgen = get_topogen()
     tc_name = request.node.name
@@ -3090,8 +3092,8 @@ def test_BGP_GR_TC_31_2_p1(request):
 
 def test_BGP_GR_TC_9_p1(request):
     """
-      Test Objective : Verify that restarting nodes reset "F" bit while sending
-      the BGP open messages after it's restarts, when BGP GR is **NOT** enabled.
+    Test Objective : Verify that restarting nodes reset "F" bit while sending
+    the BGP open messages after it's restarts, when BGP GR is **NOT** enabled.
     """
 
     tgen = get_topogen()
@@ -3264,8 +3266,8 @@ def test_BGP_GR_TC_9_p1(request):
 
 def test_BGP_GR_TC_17_p1(request):
     """
-      Test Objective : Verify that only GR helper routers keep the stale
-       route entries, not any GR disabled router.
+    Test Objective : Verify that only GR helper routers keep the stale
+     route entries, not any GR disabled router.
     """
 
     tgen = get_topogen()
@@ -3467,7 +3469,13 @@ def test_BGP_GR_TC_43_p1(request):
     step("Configure R1 and R2 as GR restarting node in global level")
 
     input_dict = {
-        "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}},
+        "r1": {
+            "bgp": {
+                "graceful-restart": {
+                    "graceful-restart": True,
+                }
+            }
+        },
         "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
     }
 
@@ -3560,7 +3568,13 @@ def test_BGP_GR_TC_43_p1(request):
     step("Verify on R2 that R1 doesn't advertise any GR capabilities")
 
     input_dict = {
-        "r1": {"bgp": {"graceful-restart": {"graceful-restart-disable": True,}}},
+        "r1": {
+            "bgp": {
+                "graceful-restart": {
+                    "graceful-restart-disable": True,
+                }
+            }
+        },
         "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
     }
 
@@ -3659,7 +3673,13 @@ def test_BGP_GR_TC_43_p1(request):
     step("Verify on R2 that R1 advertises GR capabilities as a restarting node")
 
     input_dict = {
-        "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}},
+        "r1": {
+            "bgp": {
+                "graceful-restart": {
+                    "graceful-restart": True,
+                }
+            }
+        },
         "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
     }
 
@@ -3779,7 +3799,13 @@ def test_BGP_GR_TC_44_p1(request):
     step("Verify on R2 that R1 advertises GR capabilities as a helper node")
 
     input_dict = {
-        "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True,}}},
+        "r1": {
+            "bgp": {
+                "graceful-restart": {
+                    "graceful-restart-helper": True,
+                }
+            }
+        },
         "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
     }
 
@@ -3849,7 +3875,13 @@ def test_BGP_GR_TC_44_p1(request):
     start_router_daemons(tgen, "r2", ["bgpd"])
 
     input_dict = {
-        "r1": {"bgp": {"graceful-restart": {"graceful-restart-disable": True,}}}
+        "r1": {
+            "bgp": {
+                "graceful-restart": {
+                    "graceful-restart-disable": True,
+                }
+            }
+        }
     }
 
     configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
@@ -3857,7 +3889,13 @@ def test_BGP_GR_TC_44_p1(request):
     step("Verify on R2 that R1 doesn't advertise any GR capabilities")
 
     input_dict = {
-        "r1": {"bgp": {"graceful-restart": {"graceful-restart-disable": True,}}},
+        "r1": {
+            "bgp": {
+                "graceful-restart": {
+                    "graceful-restart-disable": True,
+                }
+            }
+        },
         "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
     }
 
@@ -3941,7 +3979,13 @@ def test_BGP_GR_TC_44_p1(request):
     step("Verify on R2 that R1 advertises GR capabilities as a helper node")
 
     input_dict = {
-        "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True,}}},
+        "r1": {
+            "bgp": {
+                "graceful-restart": {
+                    "graceful-restart-helper": True,
+                }
+            }
+        },
         "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
     }
 
@@ -4108,14 +4152,28 @@ def test_BGP_GR_TC_45_p1(request):
 
     start_router_daemons(tgen, "r1", ["bgpd"])
 
-    input_dict = {"r1": {"bgp": {"graceful-restart": {"graceful-restart": False,}}}}
+    input_dict = {
+        "r1": {
+            "bgp": {
+                "graceful-restart": {
+                    "graceful-restart": False,
+                }
+            }
+        }
+    }
 
     configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
 
     step("Verify on R2 that R1 advertises GR capabilities as a helper node")
 
     input_dict = {
-        "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True,}}},
+        "r1": {
+            "bgp": {
+                "graceful-restart": {
+                    "graceful-restart-helper": True,
+                }
+            }
+        },
         "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
     }
 
@@ -4199,14 +4257,28 @@ def test_BGP_GR_TC_45_p1(request):
 
     start_router_daemons(tgen, "r2", ["bgpd"])
 
-    input_dict = {"r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}}}
+    input_dict = {
+        "r1": {
+            "bgp": {
+                "graceful-restart": {
+                    "graceful-restart": True,
+                }
+            }
+        }
+    }
 
     configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
 
     step("Verify on R2 that R1 advertises GR capabilities as a restarting node")
 
     input_dict = {
-        "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}},
+        "r1": {
+            "bgp": {
+                "graceful-restart": {
+                    "graceful-restart": True,
+                }
+            }
+        },
         "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
     }
 
@@ -4307,7 +4379,9 @@ def test_BGP_GR_TC_46_p1(request):
     input_dict = {
         "r1": {
             "bgp": {
-                "graceful-restart": {"graceful-restart": True,},
+                "graceful-restart": {
+                    "graceful-restart": True,
+                },
                 "address_family": {
                     "ipv4": {
                         "unicast": {
@@ -4559,7 +4633,9 @@ def test_BGP_GR_TC_47_p1(request):
     input_dict = {
         "r1": {
             "bgp": {
-                "graceful-restart": {"graceful-restart": True,},
+                "graceful-restart": {
+                    "graceful-restart": True,
+                },
                 "address_family": {
                     "ipv4": {
                         "unicast": {
@@ -4698,7 +4774,13 @@ def test_BGP_GR_TC_47_p1(request):
     step("Verify on R2 that R1 still advertises GR capabilities as a restarting node")
 
     input_dict = {
-        "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}},
+        "r1": {
+            "bgp": {
+                "graceful-restart": {
+                    "graceful-restart": True,
+                }
+            }
+        },
         "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
     }
 
@@ -4814,7 +4896,9 @@ def test_BGP_GR_TC_48_p1(request):
     input_dict = {
         "r1": {
             "bgp": {
-                "graceful-restart": {"graceful-restart": True,},
+                "graceful-restart": {
+                    "graceful-restart": True,
+                },
                 "address_family": {
                     "ipv4": {
                         "unicast": {
@@ -4960,7 +5044,13 @@ def test_BGP_GR_TC_48_p1(request):
     step("Verify on R2 that R1 advertises GR capabilities as a restarting node")
 
     input_dict = {
-        "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}},
+        "r1": {
+            "bgp": {
+                "graceful-restart": {
+                    "graceful-restart": True,
+                }
+            }
+        },
         "r2": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}},
     }
 
index 6926121a6b5d6eeb703e8a1c5fad5b5a592e41c5..2ddeab13f635384e32a7466ca0ae6dfdc42862ea 100644 (file)
@@ -456,7 +456,9 @@ def test_BGP_GR_TC_3_p0(request):
     input_dict = {
         "r1": {
             "bgp": {
-                "graceful-restart": {"disable-eor": True,},
+                "graceful-restart": {
+                    "disable-eor": True,
+                },
                 "address_family": {
                     "ipv4": {
                         "unicast": {
@@ -2095,7 +2097,10 @@ def test_BGP_GR_chaos_33_p1(request):
                     "ipv4": {
                         "unicast": {
                             "advertise_networks": [
-                                {"network": "200.0.20.1/32", "no_of_network": 2,}
+                                {
+                                    "network": "200.0.20.1/32",
+                                    "no_of_network": 2,
+                                }
                             ]
                         }
                     },
@@ -2207,13 +2212,13 @@ def test_BGP_GR_chaos_33_p1(request):
             else:
                 next_hop_6 = NEXT_HOP_6[1]
 
-            result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_6,
-                                expected=False)
-            assert result is not True,\
-                "Testcase {} :Failed \n Error {}". \
-                     format(tc_name, result)
-            logger.info(" Expected behavior: {}".\
-                format(result))
+            result = verify_rib(
+                tgen, addr_type, dut, input_dict_2, next_hop_6, expected=False
+            )
+            assert result is not True, "Testcase {} :Failed \n Error {}".format(
+                tc_name, result
+            )
+            logger.info(" Expected behavior: {}".format(result))
 
     logger.info("[Step 4] : Start BGPd daemon on R1 and R4..")
 
@@ -3960,7 +3965,13 @@ def test_BGP_GR_21_p2(request):
                 }
             }
         },
-        "r2": {"bgp": {"graceful-restart": {"graceful-restart": True,}}},
+        "r2": {
+            "bgp": {
+                "graceful-restart": {
+                    "graceful-restart": True,
+                }
+            }
+        },
     }
 
     configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
index 3f1157ad72a237dafcba5368ce1a5265ed5ef42c..0deb181f3e5c360ee58a4abcc80c6bebbba60d4f 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 luCommand(
     "r1", 'vtysh -c "show bgp next"', "99.0.0.. valid", "wait", "See CE static NH"
index ea059c576e0fdee2b5f67c0baf547b1faa88fa8b..789f93b837e2544d5889d1e7541eb17ce322e602 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 luCommand("ce1", "ping 192.168.1.1 -c 1", " 0. packet loss", "pass", "CE->PE ping")
 luCommand("ce2", "ping 192.168.1.1 -c 1", " 0. packet loss", "pass", "CE->PE ping")
index 96b497826172190f09c899b9e687ac072cbaf020..af39a951b7d741ec431b7a02c7732698c8213f3e 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 luCommand(
     "ce1",
index 9f21d999136825b2d206b8853fcd4f6d7163e6e5..38eac14c641b30df3db3967410138d5a611cd548 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 luCommand(
     "r1",
index 5c7427763de2c9e48960f9720a7543c2393d67a4..375bca8a633afde3acd598956624e2fbfc842702 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 luCommand(
     "r1", 'vtysh -c "add vrf r1-cust1 prefix 99.0.0.1/32"', ".", "none", "IP Address"
index 53cf353fa04849600b697192cf432473c3665b2b..f5145753a5012de410e1ba4a79f59c23a4346fbe 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 luCommand("ce1", 'vtysh -c "show bgp summary"', " 00:0", "wait", "Adjacencies up", 180)
 luCommand("ce2", 'vtysh -c "show bgp summary"', " 00:0", "wait", "Adjacencies up", 180)
index 20113b1058dd53b24d31fcae6999a3e7d58ec5f0..a5f95f94bf38dadcadced75f93d628417bf9da8b 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand, luLast
+from lib.lutil import luCommand, luLast
 from lib import topotest
 
 ret = luCommand(
index b552ea04068b27cbce4bae0b752960c26dd8e9e5..7c154ecd1540a37acbc6e4b0eaf8af39e916bab7 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 from customize import l3mdev_accept
 
 l3mdev_rtrs = ["r1", "r3", "r4", "ce4"]
index 98d2a3bafc3f2103eb76b20aecd607c4216adb86..d55169a19efceed85c8edf7f38a4b7ba0289c5f5 100644 (file)
@@ -1,5 +1,5 @@
-from lutil import luCommand
-from bgprib import bgpribRequireVpnRoutes, bgpribRequireUnicastRoutes
+from lib.lutil import luCommand
+from lib.bgprib import bgpribRequireVpnRoutes, bgpribRequireUnicastRoutes
 
 ########################################################################
 # CE routers: contain routes they originate
index af77ab01c152a5d030ab152e1961d64287123ce2..a27b1785480a4dbec83970f5734b9c119eafcae4 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 luCommand(
     "r1",
index 477578bdbd136d2184cbd874aaae64ad0186d17c..fcbc3df6ef8f914fd79ced37322dfeec8a8301bc 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 luCommand(
     "r1",
index 2b0a85a91aa81f14b9da625c95c37ee86e6d2998..dd2e24722fa9a87f52e21ab7358781abd654bf14 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 rtrs = ["ce1", "ce2", "ce3", "r1", "r2", "r3", "r4"]
 for rtr in rtrs:
index 7990533f3a4f3ebaa120228168ee52d2501ee738..6ce81baf11dde43da8f3f087e8cf6278436d8952 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 ret = luCommand(
     "ce1",
index 3c768640a1bf5d488a6fcdca4782cc7ec0927719..04ca03973d5041937f2721d20e2ba448cf365800 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 num = 50000
 b = int(num / (256 * 256))
index 40489f438f6892916fc5c850eef6e0b5feed1dc9..31fbdcd4b5a02b4c4fd0556e63825d966dd64f59 100644 (file)
@@ -1174,6 +1174,39 @@ def test_large_community_boundary_values(request):
     )
 
 
+def test_large_community_invalid_chars(request):
+    """
+    BGP canonical lcommunities must only be digits
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Don"t run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    input_dict = {
+        "r4": {
+            "bgp_community_lists": [
+                {
+                    "community_type": "standard",
+                    "action": "permit",
+                    "name": "ANY",
+                    "value": "1:a:2",
+                    "large": True,
+                }
+            ]
+        }
+    }
+
+    step("Checking boundary value for community 1:a:2")
+    result = create_bgp_community_lists(tgen, input_dict)
+    assert result is not True, "Test case {} : Failed \n Error: {}".format(
+        tc_name, result
+    )
+
+
 def test_large_community_after_clear_bgp(request):
     """
     Clear BGP neighbor-ship and check if large community and community
index 9c0355a3e9b2bcbd0ae45b20a82768afc1ceddc4..c2858a4bd06e262f7fc306812da7e709db1ae5bd 100644 (file)
@@ -2132,7 +2132,11 @@ def test_large_community_lists_with_rmap_match_regex(request):
                     {
                         "action": "permit",
                         "seq_id": "10",
-                        "match": {"large_community_list": {"id": "ALL",},},
+                        "match": {
+                            "large_community_list": {
+                                "id": "ALL",
+                            },
+                        },
                     }
                 ]
             }
@@ -2208,7 +2212,11 @@ def test_large_community_lists_with_rmap_match_regex(request):
                     {
                         "action": "permit",
                         "seq_id": "20",
-                        "match": {"large_community_list": {"id": "EXP_ALL",},},
+                        "match": {
+                            "large_community_list": {
+                                "id": "EXP_ALL",
+                            },
+                        },
                     }
                 ]
             }
diff --git a/tests/topotests/bgp_listen_on_multiple_addresses/bgp_listen_on_multiple_addresses.json b/tests/topotests/bgp_listen_on_multiple_addresses/bgp_listen_on_multiple_addresses.json
new file mode 100644 (file)
index 0000000..95de8cc
--- /dev/null
@@ -0,0 +1,154 @@
+{
+    "ipv4base": "10.0.0.0",
+    "ipv4mask": 24,
+    "ipv6base": "fd00::",
+    "ipv6mask": 64,
+    "link_ip_start": {
+        "ipv4": "10.0.0.0",
+        "v4mask": 24,
+        "ipv6": "fd00::",
+        "v6mask": 64
+    },
+    "lo_prefix": {
+        "ipv4": "1.0.",
+        "v4mask": 32,
+        "ipv6": "2001:DB8:F::",
+        "v6mask": 128
+    },
+    "routers": {
+        "r1": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                       "local_as": "1000",
+                       "address_family": {
+                           "ipv4": {
+                               "unicast": {
+                                   "neighbor": {
+                                       "r2": {
+                                           "dest_link": {
+                                               "r1": {}
+                                           }
+                                       }
+                                   }
+                               }
+                           }
+                       }
+                   }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "2000",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r1": {
+                                    "dest_link": {
+                                        "r2": {}
+                                    }
+                                },
+                                "r3": {
+                                    "dest_link": {
+                                        "r2": {}
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+           },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "2000",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3": {}
+                                    }
+                                },
+                                "r4": {
+                                    "dest_link": {
+                                        "r3": {}
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "r4": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "3000",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+                                    "dest_link": {
+                                        "r4": {}
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/tests/topotests/bgp_listen_on_multiple_addresses/test_bgp_listen_on_multiple_addresses.py b/tests/topotests/bgp_listen_on_multiple_addresses/test_bgp_listen_on_multiple_addresses.py
new file mode 100755 (executable)
index 0000000..d773e87
--- /dev/null
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_listen_on_multiple_addresses.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2021 by Boeing Defence Australia
+# Adriano Marto Reis
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bgp_listen_on_multiple_addresses.py: Test BGP daemon listening for
+connections on multiple addresses.
+
+    +------+        +------+        +------+        +------+
+    |      |        |      |        |      |        |      |
+    |  r1  |--------|  r2  |--------|  r3  |--------|  r4  |
+    |      |        |      |        |      |        |      |
+    +------+        +------+        +------+        +------+
+
+  |            |                                |             |
+  |  AS 1000   |            AS 2000             |   AS 3000   |
+  |            |                                |             |
+  +------------+--------------------------------+-------------+
+"""
+
+import os
+import sys
+import json
+import pytest
+
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+from lib.topogen import Topogen, get_topogen
+from lib.topojson import build_topo_from_json, build_config_from_json
+from lib.common_config import start_topology
+from lib.topotest import router_json_cmp, run_and_expect
+from mininet.topo import Topo
+from functools import partial
+
+
+LISTEN_ADDRESSES = {
+    "r1": ["10.0.0.1"],
+    "r2": ["10.0.0.2", "10.0.1.1"],
+    "r3": ["10.0.1.2", "10.0.2.1"],
+    "r4": ["10.0.2.2"],
+}
+
+
+# Reads data from JSON File for topology and configuration creation.
+jsonFile = "{}/bgp_listen_on_multiple_addresses.json".format(CWD)
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+
+
+class TemplateTopo(Topo):
+    "Topology builder."
+
+    def build(self, *_args, **_opts):
+        "Defines the allocation and relationship between routers and switches."
+        tgen = get_topogen(self)
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    "Sets up the test environment."
+    tgen = Topogen(TemplateTopo, mod.__name__)
+
+    # Adds extra parameters to bgpd so they listen for connections on specific
+    # multiple addresses.
+    for router_name in tgen.routers().keys():
+        tgen.net[router_name].daemons_options["bgpd"] = "-l " + " -l ".join(
+            LISTEN_ADDRESSES[router_name]
+        )
+
+    start_topology(tgen)
+    build_config_from_json(tgen, topo)
+
+
+def teardown_module(_mod):
+    "Tears-down the test environment."
+    tgen = get_topogen()
+    tgen.stop_topology()
+
+
+def test_peering():
+    "Checks if the routers peer-up."
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    _bgp_converge_initial("r1", "10.0.0.2")
+    _bgp_converge_initial("r2", "10.0.0.1")
+    _bgp_converge_initial("r2", "10.0.1.2")
+    _bgp_converge_initial("r3", "10.0.1.1")
+    _bgp_converge_initial("r3", "10.0.2.2")
+    _bgp_converge_initial("r4", "10.0.2.1")
+
+
+def test_listening_address():
+    """
+    Checks if bgpd is only listening on the specified IP addresses.
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for router in tgen.routers().values():
+        # bgpd must not be listening on the default address.
+        output = router.run("netstat -nlt4 | grep 0.0.0.0:179")
+        assert output == "", "{}: bpgd is listening on 0.0.0.0:179".format(router.name)
+
+        # bgpd must be listening on the specified addresses.
+        for address in LISTEN_ADDRESSES[router.name]:
+            output = router.run("netstat -nlt4 | grep {}:179".format(address))
+            assert output != "", "{}: bpgd is not listening on {}:179".format(
+                router.name, address
+            )
+
+
+def _bgp_converge_initial(router_name, peer_address, timeout=180):
+    """
+    Waits for the BGP connection between a given router and a given peer
+    (specified by its IP address) to be established. If the connection is
+    not established within a given timeout, then an exception is raised. 
+    """
+    tgen = get_topogen()
+    router = tgen.routers()[router_name]
+    expected = {"ipv4Unicast": {"peers": {peer_address: {"state": "Established"}}}}
+
+    test_func = partial(router_json_cmp, router, "show ip bgp summary json", expected)
+    _, result = run_and_expect(test_func, None, count=timeout, wait=1)
+    assert result is None, "{}: Failed to establish connection with {}".format(
+        router_name, peer_address
+    )
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_lu_topo1/R1/bgpd.conf b/tests/topotests/bgp_lu_topo1/R1/bgpd.conf
new file mode 100644 (file)
index 0000000..1bdb4c7
--- /dev/null
@@ -0,0 +1,21 @@
+!
+debug bgp labelpool
+debug bgp zebra
+!
+router bgp 1
+ bgp router-id 10.0.0.1
+ timers bgp 3 9
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.0.2 remote-as 2
+ neighbor 10.0.0.2 solo
+ neighbor 10.0.0.2 timers connect 10
+!
+ address-family ipv4 unicast
+  no neighbor 10.0.0.2 activate
+ exit-address-family
+ !
+ address-family ipv4 labeled-unicast
+  neighbor 10.0.0.2 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_lu_topo1/R1/labelpool.summ.json b/tests/topotests/bgp_lu_topo1/R1/labelpool.summ.json
new file mode 100644 (file)
index 0000000..29e6c2c
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "Ledger":506,
+  "InUse":506,
+  "Requests":0,
+  "LabelChunks":11,
+  "Pending":0,
+  "Reconnects":0
+}
diff --git a/tests/topotests/bgp_lu_topo1/R1/zebra.conf b/tests/topotests/bgp_lu_topo1/R1/zebra.conf
new file mode 100644 (file)
index 0000000..4f6fee5
--- /dev/null
@@ -0,0 +1,6 @@
+debug zebra events
+debug zebra dplane
+debug zebra mpls
+!
+interface R1-eth0
+ ip address 10.0.0.1/24
diff --git a/tests/topotests/bgp_lu_topo1/R2/bgpd.conf b/tests/topotests/bgp_lu_topo1/R2/bgpd.conf
new file mode 100644 (file)
index 0000000..bac608e
--- /dev/null
@@ -0,0 +1,23 @@
+debug bgp labelpool
+debug bgp zebra
+!
+router bgp 2
+ bgp router-id 10.0.0.2
+ timers bgp 3 9
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.1.3 remote-as 2
+ neighbor 10.0.1.3 update-source 10.0.1.2
+ neighbor 10.0.1.3 timers connect 10
+ neighbor 10.0.0.1 remote-as 1
+ neighbor 10.0.0.1 timers connect 10
+!
+ address-family ipv4 unicast
+  neighbor 10.0.1.3 activate
+  no neighbor 10.0.0.1 activate
+ exit-address-family
+ !
+ address-family ipv4 labeled-unicast
+  neighbor 10.0.0.1 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json b/tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json
new file mode 100644 (file)
index 0000000..29e6c2c
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "Ledger":506,
+  "InUse":506,
+  "Requests":0,
+  "LabelChunks":11,
+  "Pending":0,
+  "Reconnects":0
+}
diff --git a/tests/topotests/bgp_lu_topo1/R2/zebra.conf b/tests/topotests/bgp_lu_topo1/R2/zebra.conf
new file mode 100644 (file)
index 0000000..33ee53e
--- /dev/null
@@ -0,0 +1,11 @@
+!
+debug zebra events
+debug zebra dplane
+debug zebra mpls
+!
+interface R2-eth0
+ ip address 10.0.0.2/24
+!
+interface R2-eth1
+ ip address 10.0.1.2/24
+!
\ No newline at end of file
diff --git a/tests/topotests/bgp_lu_topo1/R3/bgpd.conf b/tests/topotests/bgp_lu_topo1/R3/bgpd.conf
new file mode 100644 (file)
index 0000000..b42df02
--- /dev/null
@@ -0,0 +1,523 @@
+log file /tmp/bgpd.log
+!
+debug bgp updates
+!
+router bgp 2
+ bgp router-id 10.0.1.3
+ timers bgp 3 9
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.1.2 remote-as 2
+ neighbor 10.0.1.2 timers connect 10
+ !
+ address-family ipv4 unicast
+  neighbor 10.0.1.2 activate
+  network 11.0.0.1/32
+  network 11.0.0.2/32
+  network 11.0.0.3/32
+  network 11.0.0.4/32
+  network 11.0.0.5/32
+  network 11.0.0.6/32
+  network 11.0.0.7/32
+  network 11.0.0.8/32
+  network 11.0.0.9/32
+  network 11.0.0.10/32
+  network 11.0.0.11/32
+  network 11.0.0.12/32
+  network 11.0.0.13/32
+  network 11.0.0.14/32
+  network 11.0.0.15/32
+  network 11.0.0.16/32
+  network 11.0.0.17/32
+  network 11.0.0.18/32
+  network 11.0.0.19/32
+  network 11.0.0.20/32
+  network 11.0.0.21/32
+  network 11.0.0.22/32
+  network 11.0.0.23/32
+  network 11.0.0.24/32
+  network 11.0.0.25/32
+  network 11.0.0.26/32
+  network 11.0.0.27/32
+  network 11.0.0.28/32
+  network 11.0.0.29/32
+  network 11.0.0.30/32
+  network 11.0.0.31/32
+  network 11.0.0.32/32
+  network 11.0.0.33/32
+  network 11.0.0.34/32
+  network 11.0.0.35/32
+  network 11.0.0.36/32
+  network 11.0.0.37/32
+  network 11.0.0.38/32
+  network 11.0.0.39/32
+  network 11.0.0.40/32
+  network 11.0.0.41/32
+  network 11.0.0.42/32
+  network 11.0.0.43/32
+  network 11.0.0.44/32
+  network 11.0.0.45/32
+  network 11.0.0.46/32
+  network 11.0.0.47/32
+  network 11.0.0.48/32
+  network 11.0.0.49/32
+  network 11.0.0.50/32
+  network 11.0.0.51/32
+  network 11.0.0.52/32
+  network 11.0.0.53/32
+  network 11.0.0.54/32
+  network 11.0.0.55/32
+  network 11.0.0.56/32
+  network 11.0.0.57/32
+  network 11.0.0.58/32
+  network 11.0.0.59/32
+  network 11.0.0.60/32
+  network 11.0.0.61/32
+  network 11.0.0.62/32
+  network 11.0.0.63/32
+  network 11.0.0.64/32
+  network 11.0.0.65/32
+  network 11.0.0.66/32
+  network 11.0.0.67/32
+  network 11.0.0.68/32
+  network 11.0.0.69/32
+  network 11.0.0.70/32
+  network 11.0.0.71/32
+  network 11.0.0.72/32
+  network 11.0.0.73/32
+  network 11.0.0.74/32
+  network 11.0.0.75/32
+  network 11.0.0.76/32
+  network 11.0.0.77/32
+  network 11.0.0.78/32
+  network 11.0.0.79/32
+  network 11.0.0.80/32
+  network 11.0.0.81/32
+  network 11.0.0.82/32
+  network 11.0.0.83/32
+  network 11.0.0.84/32
+  network 11.0.0.85/32
+  network 11.0.0.86/32
+  network 11.0.0.87/32
+  network 11.0.0.88/32
+  network 11.0.0.89/32
+  network 11.0.0.90/32
+  network 11.0.0.91/32
+  network 11.0.0.92/32
+  network 11.0.0.93/32
+  network 11.0.0.94/32
+  network 11.0.0.95/32
+  network 11.0.0.96/32
+  network 11.0.0.97/32
+  network 11.0.0.98/32
+  network 11.0.0.99/32
+  network 11.0.0.100/32
+  network 11.0.0.101/32
+  network 11.0.0.102/32
+  network 11.0.0.103/32
+  network 11.0.0.104/32
+  network 11.0.0.105/32
+  network 11.0.0.106/32
+  network 11.0.0.107/32
+  network 11.0.0.108/32
+  network 11.0.0.109/32
+  network 11.0.0.110/32
+  network 11.0.0.111/32
+  network 11.0.0.112/32
+  network 11.0.0.113/32
+  network 11.0.0.114/32
+  network 11.0.0.115/32
+  network 11.0.0.116/32
+  network 11.0.0.117/32
+  network 11.0.0.118/32
+  network 11.0.0.119/32
+  network 11.0.0.120/32
+  network 11.0.0.121/32
+  network 11.0.0.122/32
+  network 11.0.0.123/32
+  network 11.0.0.124/32
+  network 11.0.0.125/32
+  network 11.0.0.126/32
+  network 11.0.0.127/32
+  network 11.0.0.128/32
+  network 11.0.0.129/32
+  network 11.0.0.130/32
+  network 11.0.0.131/32
+  network 11.0.0.132/32
+  network 11.0.0.133/32
+  network 11.0.0.134/32
+  network 11.0.0.135/32
+  network 11.0.0.136/32
+  network 11.0.0.137/32
+  network 11.0.0.138/32
+  network 11.0.0.139/32
+  network 11.0.0.140/32
+  network 11.0.0.141/32
+  network 11.0.0.142/32
+  network 11.0.0.143/32
+  network 11.0.0.144/32
+  network 11.0.0.145/32
+  network 11.0.0.146/32
+  network 11.0.0.147/32
+  network 11.0.0.148/32
+  network 11.0.0.149/32
+  network 11.0.0.150/32
+  network 11.0.0.151/32
+  network 11.0.0.152/32
+  network 11.0.0.153/32
+  network 11.0.0.154/32
+  network 11.0.0.155/32
+  network 11.0.0.156/32
+  network 11.0.0.157/32
+  network 11.0.0.158/32
+  network 11.0.0.159/32
+  network 11.0.0.160/32
+  network 11.0.0.161/32
+  network 11.0.0.162/32
+  network 11.0.0.163/32
+  network 11.0.0.164/32
+  network 11.0.0.165/32
+  network 11.0.0.166/32
+  network 11.0.0.167/32
+  network 11.0.0.168/32
+  network 11.0.0.169/32
+  network 11.0.0.170/32
+  network 11.0.0.171/32
+  network 11.0.0.172/32
+  network 11.0.0.173/32
+  network 11.0.0.174/32
+  network 11.0.0.175/32
+  network 11.0.0.176/32
+  network 11.0.0.177/32
+  network 11.0.0.178/32
+  network 11.0.0.179/32
+  network 11.0.0.180/32
+  network 11.0.0.181/32
+  network 11.0.0.182/32
+  network 11.0.0.183/32
+  network 11.0.0.184/32
+  network 11.0.0.185/32
+  network 11.0.0.186/32
+  network 11.0.0.187/32
+  network 11.0.0.188/32
+  network 11.0.0.189/32
+  network 11.0.0.190/32
+  network 11.0.0.191/32
+  network 11.0.0.192/32
+  network 11.0.0.193/32
+  network 11.0.0.194/32
+  network 11.0.0.195/32
+  network 11.0.0.196/32
+  network 11.0.0.197/32
+  network 11.0.0.198/32
+  network 11.0.0.199/32
+  network 11.0.0.200/32
+  network 11.0.0.201/32
+  network 11.0.0.202/32
+  network 11.0.0.203/32
+  network 11.0.0.204/32
+  network 11.0.0.205/32
+  network 11.0.0.206/32
+  network 11.0.0.207/32
+  network 11.0.0.208/32
+  network 11.0.0.209/32
+  network 11.0.0.210/32
+  network 11.0.0.211/32
+  network 11.0.0.212/32
+  network 11.0.0.213/32
+  network 11.0.0.214/32
+  network 11.0.0.215/32
+  network 11.0.0.216/32
+  network 11.0.0.217/32
+  network 11.0.0.218/32
+  network 11.0.0.219/32
+  network 11.0.0.220/32
+  network 11.0.0.221/32
+  network 11.0.0.222/32
+  network 11.0.0.223/32
+  network 11.0.0.224/32
+  network 11.0.0.225/32
+  network 11.0.0.226/32
+  network 11.0.0.227/32
+  network 11.0.0.228/32
+  network 11.0.0.229/32
+  network 11.0.0.230/32
+  network 11.0.0.231/32
+  network 11.0.0.232/32
+  network 11.0.0.233/32
+  network 11.0.0.234/32
+  network 11.0.0.235/32
+  network 11.0.0.236/32
+  network 11.0.0.237/32
+  network 11.0.0.238/32
+  network 11.0.0.239/32
+  network 11.0.0.240/32
+  network 11.0.0.241/32
+  network 11.0.0.242/32
+  network 11.0.0.243/32
+  network 11.0.0.244/32
+  network 11.0.0.245/32
+  network 11.0.0.246/32
+  network 11.0.0.247/32
+  network 11.0.0.248/32
+  network 11.0.0.249/32
+  network 11.0.0.250/32
+  network 11.0.0.251/32
+  network 11.0.0.252/32
+  network 11.0.0.253/32
+  network 11.0.1.1/32
+  network 11.0.1.2/32
+  network 11.0.1.3/32
+  network 11.0.1.4/32
+  network 11.0.1.5/32
+  network 11.0.1.6/32
+  network 11.0.1.7/32
+  network 11.0.1.8/32
+  network 11.0.1.9/32
+  network 11.0.1.10/32
+  network 11.0.1.11/32
+  network 11.0.1.12/32
+  network 11.0.1.13/32
+  network 11.0.1.14/32
+  network 11.0.1.15/32
+  network 11.0.1.16/32
+  network 11.0.1.17/32
+  network 11.0.1.18/32
+  network 11.0.1.19/32
+  network 11.0.1.20/32
+  network 11.0.1.21/32
+  network 11.0.1.22/32
+  network 11.0.1.23/32
+  network 11.0.1.24/32
+  network 11.0.1.25/32
+  network 11.0.1.26/32
+  network 11.0.1.27/32
+  network 11.0.1.28/32
+  network 11.0.1.29/32
+  network 11.0.1.30/32
+  network 11.0.1.31/32
+  network 11.0.1.32/32
+  network 11.0.1.33/32
+  network 11.0.1.34/32
+  network 11.0.1.35/32
+  network 11.0.1.36/32
+  network 11.0.1.37/32
+  network 11.0.1.38/32
+  network 11.0.1.39/32
+  network 11.0.1.40/32
+  network 11.0.1.41/32
+  network 11.0.1.42/32
+  network 11.0.1.43/32
+  network 11.0.1.44/32
+  network 11.0.1.45/32
+  network 11.0.1.46/32
+  network 11.0.1.47/32
+  network 11.0.1.48/32
+  network 11.0.1.49/32
+  network 11.0.1.50/32
+  network 11.0.1.51/32
+  network 11.0.1.52/32
+  network 11.0.1.53/32
+  network 11.0.1.54/32
+  network 11.0.1.55/32
+  network 11.0.1.56/32
+  network 11.0.1.57/32
+  network 11.0.1.58/32
+  network 11.0.1.59/32
+  network 11.0.1.60/32
+  network 11.0.1.61/32
+  network 11.0.1.62/32
+  network 11.0.1.63/32
+  network 11.0.1.64/32
+  network 11.0.1.65/32
+  network 11.0.1.66/32
+  network 11.0.1.67/32
+  network 11.0.1.68/32
+  network 11.0.1.69/32
+  network 11.0.1.70/32
+  network 11.0.1.71/32
+  network 11.0.1.72/32
+  network 11.0.1.73/32
+  network 11.0.1.74/32
+  network 11.0.1.75/32
+  network 11.0.1.76/32
+  network 11.0.1.77/32
+  network 11.0.1.78/32
+  network 11.0.1.79/32
+  network 11.0.1.80/32
+  network 11.0.1.81/32
+  network 11.0.1.82/32
+  network 11.0.1.83/32
+  network 11.0.1.84/32
+  network 11.0.1.85/32
+  network 11.0.1.86/32
+  network 11.0.1.87/32
+  network 11.0.1.88/32
+  network 11.0.1.89/32
+  network 11.0.1.90/32
+  network 11.0.1.91/32
+  network 11.0.1.92/32
+  network 11.0.1.93/32
+  network 11.0.1.94/32
+  network 11.0.1.95/32
+  network 11.0.1.96/32
+  network 11.0.1.97/32
+  network 11.0.1.98/32
+  network 11.0.1.99/32
+  network 11.0.1.100/32
+  network 11.0.1.101/32
+  network 11.0.1.102/32
+  network 11.0.1.103/32
+  network 11.0.1.104/32
+  network 11.0.1.105/32
+  network 11.0.1.106/32
+  network 11.0.1.107/32
+  network 11.0.1.108/32
+  network 11.0.1.109/32
+  network 11.0.1.110/32
+  network 11.0.1.111/32
+  network 11.0.1.112/32
+  network 11.0.1.113/32
+  network 11.0.1.114/32
+  network 11.0.1.115/32
+  network 11.0.1.116/32
+  network 11.0.1.117/32
+  network 11.0.1.118/32
+  network 11.0.1.119/32
+  network 11.0.1.120/32
+  network 11.0.1.121/32
+  network 11.0.1.122/32
+  network 11.0.1.123/32
+  network 11.0.1.124/32
+  network 11.0.1.125/32
+  network 11.0.1.126/32
+  network 11.0.1.127/32
+  network 11.0.1.128/32
+  network 11.0.1.129/32
+  network 11.0.1.130/32
+  network 11.0.1.131/32
+  network 11.0.1.132/32
+  network 11.0.1.133/32
+  network 11.0.1.134/32
+  network 11.0.1.135/32
+  network 11.0.1.136/32
+  network 11.0.1.137/32
+  network 11.0.1.138/32
+  network 11.0.1.139/32
+  network 11.0.1.140/32
+  network 11.0.1.141/32
+  network 11.0.1.142/32
+  network 11.0.1.143/32
+  network 11.0.1.144/32
+  network 11.0.1.145/32
+  network 11.0.1.146/32
+  network 11.0.1.147/32
+  network 11.0.1.148/32
+  network 11.0.1.149/32
+  network 11.0.1.150/32
+  network 11.0.1.151/32
+  network 11.0.1.152/32
+  network 11.0.1.153/32
+  network 11.0.1.154/32
+  network 11.0.1.155/32
+  network 11.0.1.156/32
+  network 11.0.1.157/32
+  network 11.0.1.158/32
+  network 11.0.1.159/32
+  network 11.0.1.160/32
+  network 11.0.1.161/32
+  network 11.0.1.162/32
+  network 11.0.1.163/32
+  network 11.0.1.164/32
+  network 11.0.1.165/32
+  network 11.0.1.166/32
+  network 11.0.1.167/32
+  network 11.0.1.168/32
+  network 11.0.1.169/32
+  network 11.0.1.170/32
+  network 11.0.1.171/32
+  network 11.0.1.172/32
+  network 11.0.1.173/32
+  network 11.0.1.174/32
+  network 11.0.1.175/32
+  network 11.0.1.176/32
+  network 11.0.1.177/32
+  network 11.0.1.178/32
+  network 11.0.1.179/32
+  network 11.0.1.180/32
+  network 11.0.1.181/32
+  network 11.0.1.182/32
+  network 11.0.1.183/32
+  network 11.0.1.184/32
+  network 11.0.1.185/32
+  network 11.0.1.186/32
+  network 11.0.1.187/32
+  network 11.0.1.188/32
+  network 11.0.1.189/32
+  network 11.0.1.190/32
+  network 11.0.1.191/32
+  network 11.0.1.192/32
+  network 11.0.1.193/32
+  network 11.0.1.194/32
+  network 11.0.1.195/32
+  network 11.0.1.196/32
+  network 11.0.1.197/32
+  network 11.0.1.198/32
+  network 11.0.1.199/32
+  network 11.0.1.200/32
+  network 11.0.1.201/32
+  network 11.0.1.202/32
+  network 11.0.1.203/32
+  network 11.0.1.204/32
+  network 11.0.1.205/32
+  network 11.0.1.206/32
+  network 11.0.1.207/32
+  network 11.0.1.208/32
+  network 11.0.1.209/32
+  network 11.0.1.210/32
+  network 11.0.1.211/32
+  network 11.0.1.212/32
+  network 11.0.1.213/32
+  network 11.0.1.214/32
+  network 11.0.1.215/32
+  network 11.0.1.216/32
+  network 11.0.1.217/32
+  network 11.0.1.218/32
+  network 11.0.1.219/32
+  network 11.0.1.220/32
+  network 11.0.1.221/32
+  network 11.0.1.222/32
+  network 11.0.1.223/32
+  network 11.0.1.224/32
+  network 11.0.1.225/32
+  network 11.0.1.226/32
+  network 11.0.1.227/32
+  network 11.0.1.228/32
+  network 11.0.1.229/32
+  network 11.0.1.230/32
+  network 11.0.1.231/32
+  network 11.0.1.232/32
+  network 11.0.1.233/32
+  network 11.0.1.234/32
+  network 11.0.1.235/32
+  network 11.0.1.236/32
+  network 11.0.1.237/32
+  network 11.0.1.238/32
+  network 11.0.1.239/32
+  network 11.0.1.240/32
+  network 11.0.1.241/32
+  network 11.0.1.242/32
+  network 11.0.1.243/32
+  network 11.0.1.244/32
+  network 11.0.1.245/32
+  network 11.0.1.246/32
+  network 11.0.1.247/32
+  network 11.0.1.248/32
+  network 11.0.1.249/32
+  network 11.0.1.250/32
+  network 11.0.1.251/32
+  network 11.0.1.252/32
+  network 11.0.1.253/32
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_lu_topo1/R3/zebra.conf b/tests/topotests/bgp_lu_topo1/R3/zebra.conf
new file mode 100644 (file)
index 0000000..524978b
--- /dev/null
@@ -0,0 +1,9 @@
+log file /tmp/zebra.log
+!
+debug zebra events
+debug zebra packet detail
+debug zebra mpls
+!
+interface R3-eth0
+ ip address 10.0.1.3/24
+!
diff --git a/tests/topotests/bgp_lu_topo1/test_bgp_lu.py b/tests/topotests/bgp_lu_topo1/test_bgp_lu.py
new file mode 100644 (file)
index 0000000..61418d7
--- /dev/null
@@ -0,0 +1,178 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_lu.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by Volta Networks
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bgp_lu.py: Test BGP LU label allocation
+"""
+
+import os
+import sys
+import json
+from functools import partial
+from time import sleep
+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, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+#Basic scenario for BGP-LU. Nodes are directly connected.
+#Node 3 is advertising many routes to 2, which advertises them
+#as BGP-LU to 1; this way we get routes with actual labels, as
+#opposed to implicit-null routes in the 2-node case.
+#
+#  AS1      BGP-LU        AS2         iBGP        AS2
+#+-----+                +-----+                 +-----+
+#|     |.1            .2|     |.2             .3|     |
+#|  1  +----------------+  2  +-----------------+  3  |
+#|     |   10.0.0.0/24  |     |   10.0.1.0/24   |     |
+#+-----+                +-----+                 +-----+
+
+class TemplateTopo(Topo):
+    "Test topology builder"
+
+    def build(self, *_args, **_opts):
+        "Build function"
+        tgen = get_topogen(self)
+
+        # This function only purpose is to define allocation and relationship
+        # between routers, switches and hosts.
+        #
+        #
+        # Create routers
+        tgen.add_router("R1")
+        tgen.add_router("R2")
+        tgen.add_router("R3")
+
+        # R1-R2
+        switch = tgen.add_switch("s1")
+        switch.add_link(tgen.gears["R1"])
+        switch.add_link(tgen.gears["R2"])
+
+        # R2-R3
+        switch = tgen.add_switch("s2")
+        switch.add_link(tgen.gears["R2"])
+        switch.add_link(tgen.gears["R3"])
+
+
+
+def setup_module(mod):
+    "Sets up the pytest environment"
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(TemplateTopo, mod.__name__)
+    # ... and here it calls Mininet initialization functions.
+    tgen.start_topology()
+
+    # This is a sample of configuration loading.
+    router_list = tgen.routers()
+
+    # For all registred routers, load the zebra configuration file
+    for rname, router in router_list.items():
+        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))
+        )
+
+    # After loading the configurations, this function loads configured daemons.
+    tgen.start_router()
+
+
+def teardown_module(mod):
+    "Teardown the pytest environment"
+    tgen = get_topogen()
+
+    # This function tears down the whole topology.
+    tgen.stop_topology()
+
+def check_labelpool(router):
+    json_file = "{}/{}/labelpool.summ.json".format(CWD, router.name)
+    expected = json.loads(open(json_file).read())
+
+    test_func = partial(topotest.router_json_cmp, router, "show bgp labelpool summary json", expected)
+    _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+    assertmsg = '"{}" JSON output mismatches - Did not converge'.format(router.name)
+    assert result is None, assertmsg
+    
+def test_converge_bgplu():
+    "Wait for protocol convergence"
+
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    #tgen.mininet_cli();
+    r1 = tgen.gears["R1"]
+    r2 = tgen.gears["R2"]
+
+    check_labelpool(r1)
+    check_labelpool(r2)
+
+def test_clear_bgplu():
+    "Wait for protocol convergence"
+
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    #tgen.mininet_cli();
+    r1 = tgen.gears["R1"]
+    r2 = tgen.gears["R2"]
+
+    r1.vtysh_cmd("clear bgp 10.0.0.2")
+    check_labelpool(r1)
+    check_labelpool(r2)
+
+    r2.vtysh_cmd("clear bgp 10.0.1.3")
+    check_labelpool(r1)
+    check_labelpool(r2)
+
+    r1.vtysh_cmd("clear bgp 10.0.0.2")
+    r2.vtysh_cmd("clear bgp 10.0.1.3")
+    check_labelpool(r1)
+    check_labelpool(r2)
+
+def test_memory_leak():
+    "Run the memory leak test and report results."
+    tgen = get_topogen()
+    if not tgen.is_memleak_enabled():
+        pytest.skip("Memory leak test/report is disabled")
+
+    tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index ab570fcc164d4a92747218cd99361eec282fd251..bcee7e1a123dc2aa88be9017ff075d2d8946fd64 100644 (file)
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "red1-link1": {}
+                                            "red1-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "red1-link1": {}
+                                            "red1-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "red1-link2": {}
+                                            "red1-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "red1-link2": {}
+                                            "red1-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "blue1-link1": {}
+                                            "blue1-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "blue1-link1": {}
+                                            "blue1-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "blue1-link2": {}
+                                            "blue1-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "blue1-link2": {}
+                                            "blue1-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "red1": {
                                         "dest_link": {
-                                            "r1-link1": {}
+                                            "r1-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r2": {
                                         "dest_link": {
                                             "r1-link1":
-                                            { "next_hop_self": true }
+                                            {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
+                                                "next_hop_self": true
+                                            }
                                         }
                                     },
                                     "r4": {
                                         "dest_link": {
-                                            "r1-link1": {}
+                                            "r1-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "red1": {
                                         "dest_link": {
-                                            "r1-link1": {}
+                                            "r1-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r2": {
                                         "dest_link": {
                                             "r1-link1":
-                                            { "next_hop_self": true }
+                                            {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
+                                                "next_hop_self": true
+                                            }
                                         }
                                     },
                                     "r4": {
                                         "dest_link": {
-                                            "r1-link1": {}
+                                            "r1-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "red1": {
                                         "dest_link": {
-                                            "r1-link2": {}
+                                            "r1-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r2": {
                                         "dest_link": {
                                             "r1-link2":
-                                            { "next_hop_self": true }
+                                            {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
+                                                "next_hop_self": true
+                                            }
                                         }
                                     },
                                     "r4": {
                                         "dest_link": {
-                                            "r1-link2": {}
+                                            "r1-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "red1": {
                                         "dest_link": {
-                                            "r1-link2": {}
+                                            "r1-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r2": {
                                         "dest_link": {
                                             "r1-link2":
-                                            { "next_hop_self": true }
+                                            {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
+                                                "next_hop_self": true
+                                            }
                                         }
                                     },
                                     "r4": {
                                         "dest_link": {
-                                            "r1-link2": {}
+                                            "r1-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "blue1": {
                                         "dest_link": {
-                                            "r1-link1": {}
+                                            "r1-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r2": {
                                         "dest_link": {
                                             "r1-link3":
-                                            { "next_hop_self": true }
+                                            {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
+                                                "next_hop_self": true
+                                            }
                                         }
                                     },
                                     "r4": {
                                         "dest_link": {
-                                            "r1-link3": {}
+                                            "r1-link3": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "blue1": {
                                         "dest_link": {
-                                            "r1-link1": {}
+                                            "r1-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r2": {
                                         "dest_link": {
                                             "r1-link3":
-                                            { "next_hop_self": true }
+                                            {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
+                                                "next_hop_self": true
+                                            }
                                         }
                                     },
                                     "r4": {
                                         "dest_link": {
-                                            "r1-link3": {}
+                                            "r1-link3": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "blue1": {
                                         "dest_link": {
-                                            "r1-link2": {}
+                                            "r1-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r2": {
                                         "dest_link": {
                                             "r1-link4":
-                                            { "next_hop_self": true }
+                                            {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
+                                                "next_hop_self": true
+                                            }
                                         }
                                     },
                                     "r4": {
                                         "dest_link": {
-                                            "r1-link4": {}
+                                            "r1-link4": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "blue1": {
                                         "dest_link": {
-                                            "r1-link2": {}
+                                            "r1-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r2": {
                                         "dest_link": {
                                             "r1-link4":
-                                            { "next_hop_self": true }
+                                            {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
+                                                "next_hop_self": true
+                                            }
                                         }
                                     },
                                     "r4": {
                                         "dest_link": {
-                                            "r1-link4": {}
+                                            "r1-link4": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "r2-link1": {}
+                                            "r2-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r3": {
                                         "dest_link": {
-                                            "r2-link1": {}
+                                            "r2-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "r2-link1": {}
+                                            "r2-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r3": {
                                         "dest_link": {
-                                            "r2-link1": {}
+                                            "r2-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "r2-link2": {}
+                                            "r2-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r3": {
                                         "dest_link": {
-                                            "r2-link2": {}
+                                            "r2-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "r2-link2": {}
+                                            "r2-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r3": {
                                         "dest_link": {
-                                            "r2-link2": {}
+                                            "r2-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "r2-link3": {}
+                                            "r2-link3": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r3": {
                                         "dest_link": {
-                                            "r2-link3": {}
+                                            "r2-link3": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "r2-link3": {}
+                                            "r2-link3": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r3": {
                                         "dest_link": {
-                                            "r2-link3": {}
+                                            "r2-link3": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "r2-link4": {}
+                                            "r2-link4": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r3": {
                                         "dest_link": {
-                                            "r2-link4": {}
+                                            "r2-link4": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "r2-link4": {}
+                                            "r2-link4": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r3": {
                                         "dest_link": {
-                                            "r2-link4": {}
+                                            "r2-link4": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r2": {
                                         "dest_link": {
-                                            "r3-link1": {}
+                                            "r3-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r4": {
                                         "dest_link": {
-                                            "r3-link1": {}
+                                            "r3-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "red2": {
                                         "dest_link": {
-                                            "r3-link1": {}
+                                            "r3-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
-                                                }]
+                                                }],
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
                                             }
                                         }
                                     },
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
-                                                }]
+                                                }],
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
                                             }
                                         }
                                     },
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
-                                                }]
+                                                }],
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
                                             }
                                         }
                                     }
                                 "neighbor": {
                                     "r2": {
                                         "dest_link": {
-                                            "r3-link2": {}
+                                            "r3-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r4": {
                                         "dest_link": {
-                                            "r3-link2": {}
+                                            "r3-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "red2": {
                                         "dest_link": {
-                                            "r3-link2": {}
+                                            "r3-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
-                                                }]
+                                                }],
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
                                             }
                                         }
                                     },
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
-                                                }]
+                                                }],
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
                                             }
                                         }
                                     },
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
-                                                }]
+                                                }],
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
                                             }
                                         }
                                     }
                                 "neighbor": {
                                     "r2": {
                                         "dest_link": {
-                                            "r3-link3": {}
+                                            "r3-link3": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r4": {
                                         "dest_link": {
-                                            "r3-link3": {}
+                                            "r3-link3": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "blue2": {
                                         "dest_link": {
-                                            "r3-link1": {}
+                                            "r3-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
-                                                }]
+                                                }],
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
                                             }
                                         }
                                     },
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
-                                                }]
+                                                }],
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
                                             }
                                         }
                                     },
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
-                                                }]
+                                                }],
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
                                             }
                                         }
                                     }
                                 "neighbor": {
                                     "r2": {
                                         "dest_link": {
-                                            "r3-link4": {}
+                                            "r3-link4": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r4": {
                                         "dest_link": {
-                                            "r3-link4": {}
+                                            "r3-link4": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "blue2": {
                                         "dest_link": {
-                                            "r3-link2": {}
+                                            "r3-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
-                                                }]
+                                                }],
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
                                             }
                                         }
                                     },
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
-                                                }]
+                                                }],
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
                                             }
                                         }
                                     },
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
-                                                }]
+                                                }],
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
                                             }
                                         }
                                     }
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "r4-link1": {}
+                                            "r4-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r3": {
                                         "dest_link": {
-                                            "r4-link1": {}
+                                            "r4-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                     "r1": {
                                         "dest_link": {
                                             "r4-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
                                     "r3": {
                                         "dest_link": {
                                             "r4-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "r4-link2": {}
+                                            "r4-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r3": {
                                         "dest_link": {
-                                            "r4-link2": {}
+                                            "r4-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                     "r1": {
                                         "dest_link": {
                                             "r4-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
                                     "r3": {
                                         "dest_link": {
                                             "r4-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "r4-link3": {}
+                                            "r4-link3": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r3": {
                                         "dest_link": {
-                                            "r4-link3": {}
+                                            "r4-link3": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                     "r1": {
                                         "dest_link": {
                                             "r4-link3": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
                                     "r3": {
                                         "dest_link": {
                                             "r4-link3": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
                                 "neighbor": {
                                     "r1": {
                                         "dest_link": {
-                                            "r4-link4": {}
+                                            "r4-link4": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     },
                                     "r3": {
                                         "dest_link": {
-                                            "r4-link4": {}
+                                            "r4-link4": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                     "r1": {
                                         "dest_link": {
                                             "r4-link4": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
                                     "r3": {
                                         "dest_link": {
                                             "r4-link4": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3,
                                                 "route_maps": [{
                                                     "name": "rmap_global",
                                                     "direction": "in"
                                 "neighbor": {
                                     "r3": {
                                         "dest_link": {
-                                            "red2-link1": {}
+                                            "red2-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r3": {
                                         "dest_link": {
-                                            "red2-link1": {}
+                                            "red2-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r3": {
                                         "dest_link": {
-                                            "red2-link2": {}
+                                            "red2-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r3": {
                                         "dest_link": {
-                                            "red2-link2": {}
+                                            "red2-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r3": {
                                         "dest_link": {
-                                            "blue2-link1": {}
+                                            "blue2-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r3": {
                                         "dest_link": {
-                                            "blue2-link1": {}
+                                            "blue2-link1": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r3": {
                                         "dest_link": {
-                                            "blue2-link2": {}
+                                            "blue2-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
                                 "neighbor": {
                                     "r3": {
                                         "dest_link": {
-                                            "blue2-link2": {}
+                                            "blue2-link2": {
+                                                "keepalivetimer": 1,
+                                                "holddowntimer": 3
+                                            }
                                         }
                                     }
                                 }
index cafe758209d7735a422e0878a77f4f14136f6b5d..19a9140c138f80bf0bb28fc66e8d4efffa1bb502 100644 (file)
@@ -35,7 +35,20 @@ CHAOS_5:
 CHAOS_9:
     Verify that all vrf instances fall back
     to backup path, if primary link goes down.
-
+CHAOS_6:
+    Restart BGPd daemon on DUT to check if all the
+    routes in respective vrfs are reinstalled..
+CHAOS_2:
+    Delete a VRF instance from DUT and check if the routes get
+    deleted from subsequent neighbour routers and appears again once VRF
+    is re-added.
+CHAOS_4:
+    Verify that VRF names are locally significant
+    to a router, and end to end connectivity depends on unique
+    virtual circuits (using VLANs or separate physical interfaces).
+CHAOS_8:
+    Restart all FRR services (reboot DUT) to check if all
+    the routes in respective vrfs are reinstalled.
 """
 
 import os
@@ -79,6 +92,10 @@ from lib.common_config import (
     check_router_status,
     apply_raw_config,
     required_linux_kernel_version,
+    kill_router_daemons,
+    start_router_daemons,
+    stop_router,
+    start_router,
 )
 
 from lib.topolog import logger
@@ -143,7 +160,7 @@ def setup_module(mod):
     * `mod`: module name
     """
     # Required linux kernel version for this suite to run.
-    result = required_linux_kernel_version("4.15")
+    result = required_linux_kernel_version("4.14")
     if result is not True:
         pytest.skip("Kernel requirements are not met")
 
@@ -348,6 +365,8 @@ def test_vrf_with_multiple_links_p1(request):
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     step("Verify routes are installed with same nexthop in different" " VRFs")
+    result = verify_bgp_convergence(tgen, topo_modify)
+    assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
 
     for addr_type in ADDR_TYPES:
         dut = "r4"
@@ -639,6 +658,9 @@ def test_vrf_with_multiple_links_p1(request):
     result = create_router_bgp(tgen, topo_modify, input_dict_5)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
+    result = verify_bgp_convergence(tgen, topo_modify)
+    assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
     for addr_type in ADDR_TYPES:
         dut = "r3"
         peer = "r2"
@@ -702,16 +724,40 @@ def test_vrf_with_multiple_links_p1(request):
                     "local_as": "200",
                     "vrf": "RED_A",
                     "address_family": {
-                        "ipv4": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
-                        "ipv6": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
+                        "ipv4": {
+                            "unicast": {
+                                "maximum_paths": {
+                                    "ebgp": MAX_PATHS,
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "maximum_paths": {
+                                    "ebgp": MAX_PATHS,
+                                }
+                            }
+                        },
                     },
                 },
                 {
                     "local_as": "200",
                     "vrf": "BLUE_A",
                     "address_family": {
-                        "ipv4": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
-                        "ipv6": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
+                        "ipv4": {
+                            "unicast": {
+                                "maximum_paths": {
+                                    "ebgp": MAX_PATHS,
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "maximum_paths": {
+                                    "ebgp": MAX_PATHS,
+                                }
+                            }
+                        },
                     },
                 },
             ]
@@ -722,6 +768,8 @@ def test_vrf_with_multiple_links_p1(request):
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     step("R3 should install prefixes from both next-hops (R2 and R4)")
+    result = verify_bgp_convergence(tgen, topo_modify)
+    assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
 
     for addr_type in ADDR_TYPES:
         dut = "r3"
@@ -982,6 +1030,9 @@ def test_vrf_with_multiple_links_p1(request):
     result = create_router_bgp(tgen, topo_modify, input_dict_6)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
+    result = verify_bgp_convergence(tgen, topo_modify)
+    assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
     for addr_type in ADDR_TYPES:
         dut = "r3"
         input_dict = {
@@ -1194,7 +1245,7 @@ def test_shut_noshut_p1(request):
     result = create_router_bgp(tgen, topo, input_dict_3)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
-    step("Api call to modfiy BGP timerse")
+    step("Api call to modfiy BGP timers")
 
     input_dict_4 = {
         "r1": {
@@ -1508,7 +1559,7 @@ def test_shut_noshut_p1(request):
             " when the interface is shut"
         )
 
-        step("Sleeping for holddowntimer+1 sec..")
+        step("Sleeping for {}+1 sec..".format(HOLDDOWNTIMER))
         sleep(HOLDDOWNTIMER + 1)
 
         result = verify_bgp_convergence(tgen, topo, expected=False)
@@ -1699,6 +1750,9 @@ def test_vrf_vlan_routing_table_p1(request):
         " have duplicate entries within VRF RED_A on router RED-1"
     )
 
+    result = verify_bgp_convergence(tgen, topo)
+    assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
     for addr_type in ADDR_TYPES:
         dut = "r3"
         input_dict_1 = {
@@ -1718,7 +1772,7 @@ def test_vrf_vlan_routing_table_p1(request):
             tc_name, result
         )
 
-    step("Api call to modfiy BGP timerse")
+    step("Api call to modfiy BGP timers")
 
     input_dict_4 = {
         "r3": {
@@ -1780,7 +1834,7 @@ def test_vrf_vlan_routing_table_p1(request):
             tc_name, result
         )
 
-        step("Sleeping for holdowntimer+1 sec..")
+        step("Sleeping for {}+1 sec..".format(HOLDDOWNTIMER))
         sleep(HOLDDOWNTIMER + 1)
 
         for addr_type in ADDR_TYPES:
@@ -1811,7 +1865,7 @@ def test_vrf_vlan_routing_table_p1(request):
         )
 
         step(
-            "After deleting VRFs ipv6 addresses wil be deleted from kernel "
+            "After deleting VRFs ipv6 addresses will be deleted from kernel "
             " Adding back ipv6 addresses"
         )
 
@@ -1829,7 +1883,7 @@ def test_vrf_vlan_routing_table_p1(request):
                 tgen, dut, intf_name, intf_ipv6, vrf, create=False
             )
 
-        step("Sleeping for holdowntimer+1 sec..")
+        step("Sleeping for {}+1 sec..".format(HOLDDOWNTIMER))
         sleep(HOLDDOWNTIMER + 1)
 
         for addr_type in ADDR_TYPES:
@@ -1923,6 +1977,9 @@ def test_vrf_route_leaking_next_hop_interface_flapping_p1(request):
     result = create_router_bgp(tgen, topo, input_dict_3)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
+    result = verify_bgp_convergence(tgen, topo)
+    assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
     step("VRF RED_A should install a route for vrf RED_B's " "loopback ip.")
     for addr_type in ADDR_TYPES:
         dut = "red1"
@@ -2011,6 +2068,1790 @@ def test_vrf_route_leaking_next_hop_interface_flapping_p1(request):
     write_test_footer(tc_name)
 
 
+def test_restart_bgpd_daemon_p1(request):
+    """
+    CHAOS_6:
+    Restart BGPd daemon on DUT to check if all the
+    routes in respective vrfs are reinstalled..
+    """
+
+    tgen = get_topogen()
+    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(
+        "Advertise unique BGP prefixes(IPv4+IPv6) from RED_1"
+        " in vrf instances(RED_A and RED_B)."
+    )
+
+    for addr_type in ADDR_TYPES:
+        input_dict_1 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_A",
+                    },
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_B",
+                    },
+                ]
+            }
+        }
+        result = create_static_routes(tgen, input_dict_1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "Advertise unique BGP prefixes(IPv4+IPv6) from BLUE_1 in"
+        " vrf instances(BLUE_A and BLUE_B)."
+    )
+
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_A",
+                    },
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_B",
+                    },
+                ]
+            }
+        }
+        result = create_static_routes(tgen, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step("Redistribute static..")
+
+    input_dict_3 = {}
+    for dut in ["red1", "blue1"]:
+        temp = {dut: {"bgp": []}}
+        input_dict_3.update(temp)
+
+        if "red" in dut:
+            VRFS = ["RED_A", "RED_B"]
+            AS_NUM = [500, 500]
+        elif "blue" in dut:
+            VRFS = ["BLUE_A", "BLUE_B"]
+            AS_NUM = [800, 800]
+
+        for vrf, as_num in zip(VRFS, AS_NUM):
+            temp[dut]["bgp"].append(
+                {
+                    "local_as": as_num,
+                    "vrf": vrf,
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        },
+                        "ipv6": {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        },
+                    },
+                }
+            )
+
+    result = create_router_bgp(tgen, topo, input_dict_3)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_bgp_convergence(tgen, topo)
+    assert result is True, "Testcase () :Failed\n Error {}".format(tc_name, result)
+
+    step("Kill BGPd daemon on R1.")
+    kill_router_daemons(tgen, "r1", ["bgpd"])
+
+    for addr_type in ADDR_TYPES:
+        dut = "r2"
+        input_dict_1 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_A",
+                    },
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_B",
+                    },
+                ]
+            }
+        }
+
+        input_dict_2 = {
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_A",
+                    },
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_B",
+                    },
+                ]
+            }
+        }
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+        assert result is not True, "Testcase {} :Failed \n Error {}".format(
+            tc_name, result
+        )
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+        assert result is not True, "Testcase {} :Failed \n Error {}".format(
+            tc_name, result
+        )
+
+    step("Bring up BGPd daemon on R1.")
+    start_router_daemons(tgen, "r1", ["bgpd"])
+
+    result = verify_bgp_convergence(tgen, topo)
+    assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        dut = "r2"
+        input_dict_1 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_A",
+                    },
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_B",
+                    },
+                ]
+            }
+        }
+
+        input_dict_2 = {
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_A",
+                    },
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_B",
+                    },
+                ]
+            }
+        }
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_1)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_2)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+def test_delete_and_re_add_vrf_p1(request):
+    """
+    CHAOS_2:
+    Delete a VRF instance from DUT and check if the routes get
+    deleted from subsequent neighbour routers and appears again once VRF
+    is re-added.
+    """
+
+    tgen = get_topogen()
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    reset_config_on_routers(tgen)
+
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    step(
+        "Advertise unique prefixes in BGP using static redistribution"
+        "for both vrfs (RED_A and RED_B) on router RED_1"
+    )
+
+    for addr_type in ADDR_TYPES:
+        input_dict_1 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_A",
+                    },
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_B",
+                    },
+                ]
+            }
+        }
+        result = create_static_routes(tgen, input_dict_1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "Advertise unique prefixes in BGP using static redistribution"
+        " for both vrfs (BLUE_A and BLUE_B) on router BLUE_1."
+    )
+
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_A",
+                    },
+                    {
+                        "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_B",
+                    },
+                ]
+            }
+        }
+        result = create_static_routes(tgen, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step("Redistribute static for vrfs RED_A and RED_B and BLUE_A and BLUE_B")
+
+    input_dict_3 = {}
+    for dut in ["red1", "blue1"]:
+        temp = {dut: {"bgp": []}}
+        input_dict_3.update(temp)
+
+        if "red" in dut:
+            VRFS = ["RED_A", "RED_B"]
+            AS_NUM = [500, 500]
+        elif "blue" in dut:
+            VRFS = ["BLUE_A", "BLUE_B"]
+            AS_NUM = [800, 800]
+
+        for vrf, as_num in zip(VRFS, AS_NUM):
+            temp[dut]["bgp"].append(
+                {
+                    "local_as": as_num,
+                    "vrf": vrf,
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        },
+                        "ipv6": {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        },
+                    },
+                }
+            )
+
+    result = create_router_bgp(tgen, topo, input_dict_3)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step("Verifying RIB and FIB before deleting VRFs")
+    result = verify_bgp_convergence(tgen, topo)
+    assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        dut = "r2"
+        input_dict_1 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_A",
+                    },
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_B",
+                    },
+                ]
+            }
+        }
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_1)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        dut = "r2"
+        input_dict_2 = {
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_A",
+                    },
+                    {
+                        "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_B",
+                    },
+                ]
+            }
+        }
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_2)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    step("Api call to modfiy BGP timers")
+
+    input_dict_4 = {
+        "r1": {
+            "bgp": [
+                {
+                    "local_as": "100",
+                    "vrf": "RED_A",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r2": {
+                                        "dest_link": {
+                                            "r1-link1": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r2": {
+                                        "dest_link": {
+                                            "r1-link1": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+                {
+                    "local_as": "100",
+                    "vrf": "RED_B",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r2": {
+                                        "dest_link": {
+                                            "r1-link2": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r2": {
+                                        "dest_link": {
+                                            "r1-link2": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+                {
+                    "local_as": "100",
+                    "vrf": "BLUE_A",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r2": {
+                                        "dest_link": {
+                                            "r1-link3": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r2": {
+                                        "dest_link": {
+                                            "r1-link3": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+                {
+                    "local_as": "100",
+                    "vrf": "BLUE_B",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r2": {
+                                        "dest_link": {
+                                            "r1-link4": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r2": {
+                                        "dest_link": {
+                                            "r1-link4": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+            ]
+        }
+    }
+
+    result = create_router_bgp(tgen, topo, input_dict_4)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        clear_bgp(tgen, addr_type, "r1", vrf=["RED_A", "RED_B", "BLUE_A", "BLUE_B"])
+
+    step("Delete vrfs RED_A and BLUE_A from R1.")
+
+    input_dict = {
+        "r1": {
+            "vrfs": [
+                {"name": "RED_A", "id": "1", "delete": True},
+                {"name": "BLUE_A", "id": "3", "delete": True},
+            ]
+        }
+    }
+
+    result = create_vrf_cfg(tgen, input_dict)
+    assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    step(
+        "R2 must not receive the prefixes(in respective vrfs)"
+        "originated from RED_1 and BLUE_1."
+    )
+
+    step("Wait for {}+1 sec..".format(HOLDDOWNTIMER))
+    sleep(HOLDDOWNTIMER + 1)
+
+    for addr_type in ADDR_TYPES:
+        dut = "r2"
+        input_dict_2 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_A",
+                    }
+                ]
+            },
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_A",
+                    }
+                ]
+            },
+        }
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+        assert result is not True, (
+            "Testcase {} :Failed \n Expected Behaviour:"
+            " Routes are not present \n Error {}".format(tc_name, result)
+        )
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+        assert result is not True, (
+            "Testcase {} :Failed \n Expected Behaviour:"
+            " Routes are not present \n Error {}".format(tc_name, result)
+        )
+
+    step("Add vrfs again RED_A and BLUE_A on R1.")
+
+    result = create_vrf_cfg(tgen, {"r1": topo["routers"]["r1"]})
+    assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    create_interfaces_cfg(tgen, {"r1": topo["routers"]["r1"]})
+    assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    step(
+        "After deleting VRFs ipv6 addresses will be deleted from kernel "
+        " Adding back ipv6 addresses"
+    )
+
+    dut = "r1"
+    vrfs = ["RED_A", "BLUE_A"]
+
+    for vrf in vrfs:
+        for c_link, c_data in topo["routers"][dut]["links"].items():
+            if c_data["vrf"] != vrf:
+                continue
+
+            intf_name = c_data["interface"]
+            intf_ipv6 = c_data["ipv6"]
+
+            create_interface_in_kernel(
+                tgen, dut, intf_name, intf_ipv6, vrf, create=False
+            )
+
+    step(
+        "R2 should now receive the prefixes(in respective vrfs)"
+        "again. Check the debugging logs as well. For verification"
+        " use same commands as mention in step-3."
+    )
+
+    for addr_type in ADDR_TYPES:
+        dut = "r2"
+        input_dict_2 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_A",
+                    }
+                ]
+            }
+        }
+
+        result = verify_bgp_convergence(tgen, topo)
+        assert result is True, "Testcase {}: Failed\n Error {}".format(tc_name, result)
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_2)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        dut = "r2"
+        input_dict_2 = {
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_A",
+                    }
+                ]
+            }
+        }
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_2)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+def test_vrf_name_significance_p1(request):
+    """
+    CHAOS_4:
+    Verify that VRF names are locally significant
+    to a router, and end to end connectivity depends on unique
+    virtual circuits (using VLANs or separate physical interfaces).
+    """
+
+    tgen = get_topogen()
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    reset_config_on_routers(tgen)
+
+    if tgen.routers_have_failure():
+        check_router_status(tgen)
+
+    step(
+        "Advertise unique prefixes in BGP using static redistribution"
+        "for both vrfs (RED_A and RED_B) on router RED_1"
+    )
+
+    for addr_type in ADDR_TYPES:
+        input_dict_1 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_A",
+                    },
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_B",
+                    },
+                ]
+            }
+        }
+        result = create_static_routes(tgen, input_dict_1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "Advertise unique prefixes in BGP using static redistribution"
+        " for both vrfs (BLUE_A and BLUE_B) on router BLUE_1."
+    )
+
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_A",
+                    },
+                    {
+                        "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_B",
+                    },
+                ]
+            }
+        }
+        result = create_static_routes(tgen, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step("Redistribute static for vrfs RED_A and RED_B and BLUE_A and BLUE_B")
+
+    input_dict_3 = {}
+    for dut in ["red1", "blue1"]:
+        temp = {dut: {"bgp": []}}
+        input_dict_3.update(temp)
+
+        if "red" in dut:
+            VRFS = ["RED_A", "RED_B"]
+            AS_NUM = [500, 500]
+        elif "blue" in dut:
+            VRFS = ["BLUE_A", "BLUE_B"]
+            AS_NUM = [800, 800]
+
+        for vrf, as_num in zip(VRFS, AS_NUM):
+            temp[dut]["bgp"].append(
+                {
+                    "local_as": as_num,
+                    "vrf": vrf,
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        },
+                        "ipv6": {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        },
+                    },
+                }
+            )
+
+    result = create_router_bgp(tgen, topo, input_dict_3)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step("Configure allowas-in on red2 and blue2")
+
+    input_dict_4 = {
+        "red2": {
+            "bgp": [
+                {
+                    "local_as": "500",
+                    "vrf": "RED_A",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "red2-link1": {
+                                                "allowas-in": {"number_occurences": 2}
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "red2-link1": {
+                                                "allowas-in": {"number_occurences": 2}
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+                {
+                    "local_as": "500",
+                    "vrf": "RED_B",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "red2-link2": {
+                                                "allowas-in": {"number_occurences": 2}
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "red2-link2": {
+                                                "allowas-in": {"number_occurences": 2}
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+            ]
+        },
+        "blue2": {
+            "bgp": [
+                {
+                    "local_as": "800",
+                    "vrf": "BLUE_A",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "blue2-link1": {
+                                                "allowas-in": {"number_occurences": 2}
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "blue2-link1": {
+                                                "allowas-in": {"number_occurences": 2}
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+                {
+                    "local_as": "800",
+                    "vrf": "BLUE_B",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "blue2-link2": {
+                                                "allowas-in": {"number_occurences": 2}
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "blue2-link2": {
+                                                "allowas-in": {"number_occurences": 2}
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+            ]
+        },
+    }
+
+    result = create_router_bgp(tgen, topo, input_dict_4)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step("Verifying RIB and FIB before deleting VRFs")
+
+    for addr_type in ADDR_TYPES:
+        dut = "red2"
+        input_dict_1 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_A",
+                    }
+                ]
+            }
+        }
+        input_dict_2 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_B",
+                    }
+                ]
+            }
+        }
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_1)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_2)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        dut = "blue2"
+        input_dict_3 = {
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_A",
+                    }
+                ]
+            }
+        }
+
+        input_dict_4 = {
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_B",
+                    }
+                ]
+            }
+        }
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_3)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_3)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    step("Api call to modfiy BGP timers")
+
+    input_dict_4 = {
+        "r3": {
+            "bgp": [
+                {
+                    "local_as": "200",
+                    "vrf": "RED_A",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "red2": {
+                                        "dest_link": {
+                                            "r3-link1": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "red2": {
+                                        "dest_link": {
+                                            "r3-link1": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+                {
+                    "local_as": "200",
+                    "vrf": "RED_B",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "red2": {
+                                        "dest_link": {
+                                            "r3-link2": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "red2": {
+                                        "dest_link": {
+                                            "r3-link2": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+                {
+                    "local_as": "200",
+                    "vrf": "BLUE_A",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "blue2": {
+                                        "dest_link": {
+                                            "r3-link1": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "blue2": {
+                                        "dest_link": {
+                                            "r3-link1": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+                {
+                    "local_as": "200",
+                    "vrf": "BLUE_B",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "blue2": {
+                                        "dest_link": {
+                                            "r3-link2": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "blue2": {
+                                        "dest_link": {
+                                            "r3-link2": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+            ]
+        },
+        "red2": {
+            "bgp": [
+                {
+                    "local_as": "500",
+                    "vrf": "RED_A",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "red2-link1": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "red2-link1": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+                {
+                    "local_as": "500",
+                    "vrf": "RED_B",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "red2-link2": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "red2-link2": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+            ]
+        },
+        "blue2": {
+            "bgp": [
+                {
+                    "local_as": "800",
+                    "vrf": "BLUE_A",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "blue2-link1": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "blue2-link1": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+                {
+                    "local_as": "800",
+                    "vrf": "BLUE_B",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "blue2-link2": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "blue2-link2": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+            ]
+        },
+    }
+
+    result = create_router_bgp(tgen, topo, input_dict_4)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        clear_bgp(tgen, addr_type, "r3", vrf=["RED_A", "RED_B", "BLUE_A", "BLUE_B"])
+
+        clear_bgp(tgen, addr_type, "red2", vrf=["RED_A", "RED_B"])
+
+        clear_bgp(tgen, addr_type, "blue2", vrf=["BLUE_A", "BLUE_B"])
+
+    step("Delete vrfs RED_A and BLUE_A from R3")
+
+    input_dict = {
+        "r3": {
+            "vrfs": [
+                {"name": "RED_A", "id": "1", "delete": True},
+                {"name": "BLUE_A", "id": "3", "delete": True},
+            ]
+        }
+    }
+
+    result = create_vrf_cfg(tgen, input_dict)
+    assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    step("Waiting for {}+1..".format(HOLDDOWNTIMER))
+    sleep(HOLDDOWNTIMER + 1)
+
+    step("Verify RIB and FIB after deleting VRFs")
+
+    for addr_type in ADDR_TYPES:
+        dut = "red2"
+        input_dict_1 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_A",
+                    }
+                ]
+            }
+        }
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+        assert (
+            result is not True
+        ), "Testcase {} :Failed \n Expected Behaviour: Routes are not"
+        " present \n Error {}".format(tc_name, result)
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+        assert (
+            result is not True
+        ), "Testcase {} :Failed \n Expected Behaviour: Routes are not"
+        " present \n Error {}".format(tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        dut = "blue2"
+        input_dict_2 = {
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_A",
+                    }
+                ]
+            }
+        }
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+        assert result is not True, (
+            "Testcase {} :Failed \n Expected Behaviour: Routes are not"
+            " present \n Error {}".format(tc_name, result)
+        )
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+        assert result is not True, (
+            "Testcase {} :Failed \n Expected Behaviour: Routes are not"
+            " present \n Error {}".format(tc_name, result)
+        )
+
+    step("Create 2 new VRFs PINK_A and GREY_A IN R3")
+
+    topo_modify = deepcopy(topo)
+    topo_modify["routers"]["r3"]["vrfs"][0]["name"] = "PINK_A"
+    topo_modify["routers"]["r3"]["vrfs"][0]["id"] = "1"
+    topo_modify["routers"]["r3"]["vrfs"][2]["name"] = "GREY_A"
+    topo_modify["routers"]["r3"]["vrfs"][2]["id"] = "3"
+
+    topo_modify["routers"]["r3"]["links"]["red2-link1"]["vrf"] = "PINK_A"
+    topo_modify["routers"]["r3"]["links"]["blue2-link1"]["vrf"] = "GREY_A"
+
+    topo_modify["routers"]["r3"]["links"]["r2-link1"]["vrf"] = "PINK_A"
+    topo_modify["routers"]["r3"]["links"]["r2-link3"]["vrf"] = "GREY_A"
+
+    topo_modify["routers"]["r3"]["links"]["r4-link1"]["vrf"] = "PINK_A"
+    topo_modify["routers"]["r3"]["links"]["r4-link3"]["vrf"] = "GREY_A"
+
+    topo_modify["routers"]["r3"]["bgp"][0]["vrf"] = "PINK_A"
+    topo_modify["routers"]["r3"]["bgp"][2]["vrf"] = "GREY_A"
+
+    result = create_vrf_cfg(tgen, {"r3": topo_modify["routers"]["r3"]})
+    assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    create_interfaces_cfg(tgen, {"r3": topo_modify["routers"]["r3"]})
+    assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    result = create_router_bgp(tgen, topo_modify["routers"])
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step("Api call to modfiy BGP timers")
+
+    input_dict_4 = {
+        "r3": {
+            "bgp": [
+                {
+                    "local_as": "200",
+                    "vrf": "PINK_A",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "red2": {
+                                        "dest_link": {
+                                            "r3-link1": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "red2": {
+                                        "dest_link": {
+                                            "r3-link1": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+                {
+                    "local_as": "200",
+                    "vrf": "RED_B",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "red2": {
+                                        "dest_link": {
+                                            "r3-link2": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "red2": {
+                                        "dest_link": {
+                                            "r3-link2": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+                {
+                    "local_as": "200",
+                    "vrf": "GREY_A",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "blue2": {
+                                        "dest_link": {
+                                            "r3-link1": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "blue2": {
+                                        "dest_link": {
+                                            "r3-link1": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+                {
+                    "local_as": "200",
+                    "vrf": "BLUE_B",
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "neighbor": {
+                                    "blue2": {
+                                        "dest_link": {
+                                            "r3-link2": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "neighbor": {
+                                    "blue2": {
+                                        "dest_link": {
+                                            "r3-link2": {
+                                                "keepalivetimer": KEEPALIVETIMER,
+                                                "holddowntimer": HOLDDOWNTIMER,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                    },
+                },
+            ]
+        }
+    }
+
+    result = create_router_bgp(tgen, topo_modify, input_dict_4)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        clear_bgp(tgen, addr_type, "r3", vrf=["PINK_A", "RED_B", "GREY_A", "BLUE_B"])
+
+    step(
+        "After deleting VRFs ipv6 addresses will be deleted from kernel "
+        " Adding back ipv6 addresses"
+    )
+
+    dut = "r3"
+    vrfs = ["GREY_A", "PINK_A"]
+
+    for vrf in vrfs:
+        for c_link, c_data in topo_modify["routers"][dut]["links"].items():
+            if c_data["vrf"] != vrf:
+                continue
+
+            intf_name = c_data["interface"]
+            intf_ipv6 = c_data["ipv6"]
+
+            create_interface_in_kernel(
+                tgen, dut, intf_name, intf_ipv6, vrf, create=False
+            )
+
+    step("Waiting for {}+1 sec..".format(HOLDDOWNTIMER))
+    sleep(HOLDDOWNTIMER + 1)
+
+    step(
+        "Advertised prefixes should appear again in respective VRF"
+        " table on routers RED_2 and BLUE_2. Verify fib and rib entries"
+    )
+
+    for addr_type in ADDR_TYPES:
+        dut = "red2"
+        input_dict_1 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_A",
+                    }
+                ]
+            }
+        }
+
+        input_dict_2 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_B",
+                    }
+                ]
+            }
+        }
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_1)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_2)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        dut = "blue2"
+        input_dict_3 = {
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_A",
+                    }
+                ]
+            }
+        }
+
+        input_dict_4 = {
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_B",
+                    }
+                ]
+            }
+        }
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_3)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_3)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+def test_restart_frr_services_p1(request):
+    """
+    CHAOS_8:
+    Restart all FRR services (reboot DUT) to check if all
+    the routes in respective vrfs are reinstalled.
+    """
+
+    tgen = get_topogen()
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    reset_config_on_routers(tgen)
+
+    if tgen.routers_have_failure():
+        check_router_status(tgen)
+
+    step(
+        "Advertise unique BGP prefixes(IPv4+IPv6) from RED_1"
+        " in vrf instances(RED_A and RED_B)."
+    )
+
+    for addr_type in ADDR_TYPES:
+        input_dict_1 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_A",
+                    },
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_B",
+                    },
+                ]
+            }
+        }
+        result = create_static_routes(tgen, input_dict_1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "Advertise unique BGP prefixes(IPv4+IPv6) from BLUE_1 in"
+        " vrf instances(BLUE_A and BLUE_B)."
+    )
+
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_A",
+                    },
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_B",
+                    },
+                ]
+            }
+        }
+        result = create_static_routes(tgen, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step("Redistribute static..")
+
+    input_dict_3 = {}
+    for dut in ["red1", "blue1"]:
+        temp = {dut: {"bgp": []}}
+        input_dict_3.update(temp)
+
+        if "red" in dut:
+            VRFS = ["RED_A", "RED_B"]
+            AS_NUM = [500, 500]
+        elif "blue" in dut:
+            VRFS = ["BLUE_A", "BLUE_B"]
+            AS_NUM = [800, 800]
+
+        for vrf, as_num in zip(VRFS, AS_NUM):
+            temp[dut]["bgp"].append(
+                {
+                    "local_as": as_num,
+                    "vrf": vrf,
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        },
+                        "ipv6": {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        },
+                    },
+                }
+            )
+
+    result = create_router_bgp(tgen, topo, input_dict_3)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step("Restart frr on R1")
+    stop_router(tgen, "r1")
+    start_router(tgen, "r1")
+
+    for addr_type in ADDR_TYPES:
+        dut = "r2"
+
+        input_dict_1 = {
+            "red1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_A",
+                    },
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "RED_B",
+                    },
+                ]
+            }
+        }
+
+        input_dict_2 = {
+            "blue1": {
+                "static_routes": [
+                    {
+                        "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_A",
+                    },
+                    {
+                        "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "vrf": "BLUE_B",
+                    },
+                ]
+            }
+        }
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_1)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_2)
+        assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+    write_test_footer(tc_name)
+
+
 if __name__ == "__main__":
     args = ["-s"] + sys.argv[1:]
     sys.exit(pytest.main(args))
index 6344f7bb406453297865e3d7ff91bab007228fd7..d8815a0d39b7e6bd64b1e96fc89f814a0158c994 100644 (file)
@@ -226,7 +226,7 @@ def test_bgp_converge():
         for i in range(1, 2):
             for view in range(1, 4):
                 notConverged = net["r%s" % i].cmd(
-                    'vtysh -c "show ip bgp view %s summary" 2> /dev/null | grep ^[0-9] | grep -vP " 11\s+(\d+)$"'
+                    'vtysh -c "show ip bgp view %s summary" 2> /dev/null | grep ^[0-9] | grep -vP " 11\s+(\d+)"'
                     % view
                 )
                 if notConverged:
@@ -332,7 +332,7 @@ def test_bgp_routingTable():
 
             if not success:
                 resultstr = "No template matched.\n"
-                for f in diffresult.iterkeys():
+                for f in diffresult.keys():
                     resultstr += (
                         "template %s: r%s failed Routing Table Check for view %s:\n%s\n"
                         % (f, i, view, diffresult[f])
diff --git a/tests/topotests/bgp_peer-group/__init__.py b/tests/topotests/bgp_peer-group/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bgp_peer-group/r1/bgpd.conf b/tests/topotests/bgp_peer-group/r1/bgpd.conf
new file mode 100644 (file)
index 0000000..19b490a
--- /dev/null
@@ -0,0 +1,8 @@
+!
+router bgp 65001
+  neighbor PG peer-group
+  neighbor PG remote-as external
+  neighbor PG timers 3 10
+  neighbor 192.168.255.3 peer-group PG
+  neighbor r1-eth0 interface peer-group PG
+!
diff --git a/tests/topotests/bgp_peer-group/r1/zebra.conf b/tests/topotests/bgp_peer-group/r1/zebra.conf
new file mode 100644 (file)
index 0000000..e2c399e
--- /dev/null
@@ -0,0 +1,6 @@
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_peer-group/r2/bgpd.conf b/tests/topotests/bgp_peer-group/r2/bgpd.conf
new file mode 100644 (file)
index 0000000..0880ee9
--- /dev/null
@@ -0,0 +1,7 @@
+!
+router bgp 65002
+  neighbor PG peer-group
+  neighbor PG remote-as external
+  neighbor PG timers 3 10
+  neighbor r2-eth0 interface peer-group PG
+!
diff --git a/tests/topotests/bgp_peer-group/r2/zebra.conf b/tests/topotests/bgp_peer-group/r2/zebra.conf
new file mode 100644 (file)
index 0000000..606c17b
--- /dev/null
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_peer-group/r3/bgpd.conf b/tests/topotests/bgp_peer-group/r3/bgpd.conf
new file mode 100644 (file)
index 0000000..eb2fca1
--- /dev/null
@@ -0,0 +1,7 @@
+!
+router bgp 65003
+  neighbor PG peer-group
+  neighbor PG remote-as external
+  neighbor PG timers 3 10
+  neighbor 192.168.255.1 peer-group PG
+!
diff --git a/tests/topotests/bgp_peer-group/r3/zebra.conf b/tests/topotests/bgp_peer-group/r3/zebra.conf
new file mode 100644 (file)
index 0000000..e9fdfb7
--- /dev/null
@@ -0,0 +1,6 @@
+!
+interface r3-eth0
+ ip address 192.168.255.3/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_peer-group/test_bgp_peer-group.py b/tests/topotests/bgp_peer-group/test_bgp_peer-group.py
new file mode 100644 (file)
index 0000000..7c7a8b8
--- /dev/null
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2021 by
+# Donatas Abraitis <donatas.abraitis@gmail.com>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Test if peer-group works for numbered and unnumbered configurations.
+"""
+
+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
+from mininet.topo import Topo
+
+
+class TemplateTopo(Topo):
+    def build(self, *_args, **_opts):
+        tgen = get_topogen(self)
+
+        for routern in range(1, 4):
+            tgen.add_router("r{}".format(routern))
+
+        switch = tgen.add_switch("s1")
+        switch.add_link(tgen.gears["r1"])
+        switch.add_link(tgen.gears["r2"])
+        switch.add_link(tgen.gears["r3"])
+
+
+def setup_module(mod):
+    tgen = Topogen(TemplateTopo, 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_peer_group():
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    def _bgp_peer_group_configured():
+        output = json.loads(tgen.gears["r1"].vtysh_cmd("show ip bgp neighbor json"))
+        expected = {
+            "r1-eth0": {"peerGroup": "PG", "bgpState": "Established"},
+            "192.168.255.3": {"peerGroup": "PG", "bgpState": "Established"},
+        }
+        return topotest.json_cmp(output, expected)
+
+    test_func = functools.partial(_bgp_peer_group_configured)
+    success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+
+    assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r1"])
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index 6d7131e1e56a7efa6356846fdfee1d8c4c32a961..ceac84709b7e382d1663d40ae8fe57da1c86693a 100644 (file)
@@ -101,7 +101,11 @@ def test_r1_receive_and_advertise_prefix_sid_type1():
             "prefix": prefix,
             "advertisedTo": {"10.0.0.101": {}, "10.0.0.102": {}},
             "paths": [
-                {"valid": True, "remoteLabel": remoteLabel, "labelIndex": labelIndex,}
+                {
+                    "valid": True,
+                    "remoteLabel": remoteLabel,
+                    "labelIndex": labelIndex,
+                }
             ],
         }
         return topotest.json_cmp(output, expected)
index 3af944473de52226faaee47d2085bd0517ca34ab..3f9009967dc13ba2230c04fc3e952a80ba5cf252 100644 (file)
@@ -1042,9 +1042,10 @@ def test_next_hop_with_recursive_lookup_p1(request):
             next_hop=next_hop,
             expected=False,
         )
-        assert result is not True, (
-            "Testcase {} : Failed \n "
-            "Route is still present \n Error : {}".format(tc_name, result)
+        assert (
+            result is not True
+        ), "Testcase {} : Failed \n " "Route is still present \n Error : {}".format(
+            tc_name, result
         )
 
     step("Re-apply redistribution on R4.")
@@ -1125,9 +1126,10 @@ def test_next_hop_with_recursive_lookup_p1(request):
             next_hop=next_hop,
             expected=False,
         )
-        assert result is not True, (
-            "Testcase {} : Failed \n "
-            "Route is still present \n Error : {}".format(tc_name, result)
+        assert (
+            result is not True
+        ), "Testcase {} : Failed \n " "Route is still present \n Error : {}".format(
+            tc_name, result
         )
 
     shutdown_bringup_interface(tgen, "r3", intf_r3_r4, True)
@@ -1182,9 +1184,10 @@ def test_next_hop_with_recursive_lookup_p1(request):
             next_hop=next_hop,
             expected=False,
         )
-        assert result is not True, (
-            "Testcase {} : Failed \n "
-            "Route is still present \n Error : {}".format(tc_name, result)
+        assert (
+            result is not True
+        ), "Testcase {} : Failed \n " "Route is still present \n Error : {}".format(
+            tc_name, result
         )
 
     shutdown_bringup_interface(tgen, "r4", intf_r4_r3, True)
@@ -2101,8 +2104,20 @@ def test_BGP_active_standby_preemption_and_ecmp_p1(request):
         "r4": {
             "bgp": {
                 "address_family": {
-                    "ipv4": {"unicast": {"maximum_paths": {"ebgp": 1,}}},
-                    "ipv6": {"unicast": {"maximum_paths": {"ebgp": 1,}}},
+                    "ipv4": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ebgp": 1,
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ebgp": 1,
+                            }
+                        }
+                    },
                 }
             }
         }
@@ -2131,8 +2146,20 @@ def test_BGP_active_standby_preemption_and_ecmp_p1(request):
         "r4": {
             "bgp": {
                 "address_family": {
-                    "ipv4": {"unicast": {"maximum_paths": {"ebgp": 2,}}},
-                    "ipv6": {"unicast": {"maximum_paths": {"ebgp": 2,}}},
+                    "ipv4": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ebgp": 2,
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ebgp": 2,
+                            }
+                        }
+                    },
                 }
             }
         }
index f4b4da55d216ec492646eeeb5d9a90003c480ca4..bc47dfc85c8eae8a67ff9c980cba9e447e7b9cac 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 holddownFactorSet = luCommand(
     "r1",
index 9fdef84cdfa2c2015c778a2162f1c31f77fac2cd..e68fac86fac6efbb9a76607d6595a5242c7b6dbe 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 holddownFactorSet = luCommand(
     "r1",
index 1caa827ce2c1e01d5253918422bd23e6aa7abfd7..24b3cba96e4704f7f9fa72bb07e1723632876c85 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 luCommand("r1", 'vtysh -c "show bgp ipv4 vpn"', "", "none", "VPN SAFI")
 luCommand("r2", 'vtysh -c "show bgp ipv4 vpn"', "", "none", "VPN SAFI")
index e68e9e93abf985d2dee44302aa9ef29a9b157d50..f5c2db25ffede2dafb6d364e222aa801e093a4e5 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 holddownFactorSet = luCommand(
     "r1",
index eea977bfaf0bc174bec4f890ef4eb7156c5a59a3..7201ac8111cb13a51e4a37bee0379914a742a47e 100644 (file)
@@ -1,4 +1,4 @@
-from lutil import luCommand
+from lib.lutil import luCommand
 
 luCommand(
     "r1",
index 0fabd90341315bb98ccec2b4765a47270f0d2d46..0467bf1bfbc1f54ec28cb8a8e5002214445c2c86 100644 (file)
@@ -415,9 +415,10 @@ def test_route_summarisation_with_summary_only_p1(request):
         result = verify_rib(
             tgen, addr_type, "r3", input_static, protocol="bgp", 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 " "Routes are still present \n Error: {}".format(
+            tc_name, result
         )
 
         result = verify_rib(tgen, addr_type, "r1", input_static_agg, protocol="bgp")
@@ -614,7 +615,9 @@ def test_route_summarisation_with_summary_only_p1(request):
                         addr_type: {
                             "unicast": {
                                 "advertise_networks": [
-                                    {"network": NETWORK_4_1[addr_type],}
+                                    {
+                                        "network": NETWORK_4_1[addr_type],
+                                    }
                                 ]
                             }
                         }
@@ -1014,7 +1017,11 @@ def test_route_summarisation_with_as_set_p1(request):
         assert result is True, "Testcase  : Failed \n Error: {}".format(tc_name, result)
 
     for addr_type in ADDR_TYPES:
-        for pfx, seq_id, network, in zip([6, 7], [60, 70], [NETWORK_3_1, NETWORK_4_1]):
+        for (
+            pfx,
+            seq_id,
+            network,
+        ) in zip([6, 7], [60, 70], [NETWORK_3_1, NETWORK_4_1]):
             prefix_list = {
                 "r1": {
                     "prefix_lists": {
index cf8be5f44f56ac35baf82783086c61860efe432c..c75055c26f8dbe4fc5d3ee6719ac145497e7fa79 100644 (file)
@@ -56,6 +56,7 @@ class TemplateTopo(Topo):
         switch.add_link(tgen.gears["r2"])
         switch.add_link(tgen.gears["r3"])
 
+
 def setup_module(mod):
     tgen = Topogen(TemplateTopo, mod.__name__)
     tgen.start_topology()
@@ -114,6 +115,7 @@ def test_bgp_route():
     assertmsg = '"r3" JSON output mismatches'
     assert result is None, assertmsg
 
+
 if __name__ == "__main__":
     args = ["-s"] + sys.argv[1:]
     sys.exit(pytest.main(args))
index 9106c163cd27ae1dfd7fbe297c6da237d0610ea5..6e7495d929a082dd127bacca22fbf9e7b5948488 100644 (file)
@@ -943,9 +943,10 @@ def test_modify_route_map_match_set_clauses_p1(request):
         }
 
         result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1, expected=False)
-        assert result is not True, (
-            "Testcase {} : Failed \n Error : Routes are still "
-            "present {}".format(tc_name, result)
+        assert (
+            result is not True
+        ), "Testcase {} : Failed \n Error : Routes are still " "present {}".format(
+            tc_name, result
         )
 
     write_test_footer(tc_name)
index ef916abcf3c7daefb480e33b7580c4fd6584e148..d25856ea62eac5a84a8534066082a6d4d10d5da1 100755 (executable)
@@ -41,6 +41,9 @@ if [[ "$1" = "-h" ]] || [[ "$1" = "--help" ]]; then
        TOPOTEST_AUTOLOAD       If set to 1, the script will try to load necessary
                                kernel modules without asking for confirmation first.
 
+       TOPOTEST_NOLOAD         If set to 1, don't try to load necessary kernel
+                               modules and don't even ask.
+
        TOPOTEST_BUILDCACHE     Docker volume used for caching multiple FRR builds
                                over container runs. By default a
                                \`topotest-buildcache\` volume will be created for
@@ -85,35 +88,37 @@ fi
 
 export PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin"
 
-for module in mpls-router mpls-iptunnel; do
-       if modprobe -n $module 2> /dev/null; then
-               :
-       else
-               # If the module doesn't exist, we cannot do anything about it
-               continue
-       fi
-
-       if [ $(grep -c ${module/-/_} /proc/modules) -ne 0 ]; then
-               # If the module is loaded, we don't have to do anything
-               continue
-       fi
+if [ "$TOPOTEST_NOLOAD" != "1" ]; then
+       for module in mpls-router mpls-iptunnel; do
+               if modprobe -n $module 2> /dev/null; then
+                       :
+               else
+                       # If the module doesn't exist, we cannot do anything about it
+                       continue
+               fi
 
-       if [ "$TOPOTEST_AUTOLOAD" != "1" ]; then
-               echo "To run all the possible tests, we need to load $module."
-               echo -n "Do you want to proceed? [y/n] "
-               read answer
-               if [ x"$answer" != x"y" ]; then
-                       echo "Not loading."
+               if [ $(grep -c ${module/-/_} /proc/modules) -ne 0 ]; then
+                       # If the module is loaded, we don't have to do anything
                        continue
                fi
-       fi
 
-       if [ x"$(whoami)" = x"root" ]; then
-               modprobe $module
-       else
-               sudo modprobe $module
-       fi
-done
+               if [ "$TOPOTEST_AUTOLOAD" != "1" ]; then
+                       echo "To run all the possible tests, we need to load $module."
+                       echo -n "Do you want to proceed? [y/n] "
+                       read answer
+                       if [ x"$answer" != x"y" ]; then
+                               echo "Not loading."
+                               continue
+                       fi
+               fi
+
+               if [ x"$(whoami)" = x"root" ]; then
+                       modprobe $module
+               else
+                       sudo modprobe $module
+               fi
+       done
+fi
 
 if [ -z "$TOPOTEST_LOGS" ]; then
        mkdir -p /tmp/topotest_logs
index 3ce1472ac0ca03653c8721c44f11c42aedde0a4d..bf94d39a4b570a3ee195d2945746bd4c637dc2c3 100644 (file)
@@ -91,7 +91,7 @@ class NetworkTopo(Topo):
 ##
 #####################################################
 
-
+@pytest.mark.eigrp
 def setup_module(module):
     "Setup topology"
     tgen = Topogen(NetworkTopo, module.__name__)
index 265124132fde5baeb909573a1fc083c031e65340..07623af063c5e808016095d08bbaf11044c3b001 100644 (file)
@@ -97,7 +97,7 @@ class NetworkTopo(Topo):
 ##
 #####################################################
 
-
+@pytest.mark.pim
 def setup_module(module):
     "Setup topology"
     tgen = Topogen(NetworkTopo, module.__name__)
diff --git a/tests/topotests/isis-lfa-topo1/__init__.py b/tests/topotests/isis-lfa-topo1/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/isis-lfa-topo1/rt1/isisd.conf b/tests/topotests/isis-lfa-topo1/rt1/isisd.conf
new file mode 100644 (file)
index 0000000..2ad8c12
--- /dev/null
@@ -0,0 +1,52 @@
+password 1
+hostname rt1
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt2
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt3
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt4
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt5
+ ipv6 router isis 1
+ isis metric 20
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt6
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+router isis 1
+ net 49.0000.0000.0000.0001.00
+ is-type level-1
+ lsp-gen-interval 2
+ topology ipv6-unicast
+ !fast-reroute lfa tiebreaker node-protecting index 10
+ !fast-reroute lfa tiebreaker downstream index 20
+ !fast-reroute lfa tiebreaker lowest-backup-metric index 30
diff --git a/tests/topotests/isis-lfa-topo1/rt1/step1/show_ipv6_route.ref b/tests/topotests/isis-lfa-topo1/rt1/step1/show_ipv6_route.ref
new file mode 100644 (file)
index 0000000..10c61d5
--- /dev/null
@@ -0,0 +1,236 @@
+{
+  "2001:db8:1000::2\/128":[
+    {
+      "prefix":"2001:db8:1000::2\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "backupIndex":[
+            0,
+            1,
+            2
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt5",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::3\/128":[
+    {
+      "prefix":"2001:db8:1000::3\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "backupIndex":[
+            0,
+            1
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt5",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::4\/128":[
+    {
+      "prefix":"2001:db8:1000::4\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt4",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt5",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::5\/128":[
+    {
+      "prefix":"2001:db8:1000::5\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt5",
+          "active":true,
+          "backupIndex":[
+            0,
+            1,
+            2,
+            3
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt4",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::6\/128":[
+    {
+      "prefix":"2001:db8:1000::6\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true,
+          "backupIndex":[
+            0,
+            1
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt5",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::7\/128":[
+    {
+      "prefix":"2001:db8:1000::7\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":25,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "backupIndex":[
+            0,
+            1,
+            2,
+            3
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt4",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt5",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/isis-lfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-lfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644 (file)
index 0000000..d8a7c5a
--- /dev/null
@@ -0,0 +1,101 @@
+{
+  "frr-interface:lib": {
+    "interface": [
+      {
+        "name": "eth-rt2",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0002",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt3",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0003",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt4",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0004",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt5",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0005",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt6",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0006",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-lfa-topo1/rt1/step10/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step10/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..d626cdc
--- /dev/null
@@ -0,0 +1,46 @@
+--- a/rt1/step9/show_ipv6_route.ref
++++ b/rt1/step10/show_ipv6_route.ref
+@@ -16,7 +16,8 @@
+           "active":true,
+           "backupIndex":[
+             0,
+-            1
++            1,
++            2
+           ]
+         }
+       ],
+@@ -30,6 +31,11 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt5",
+           "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt6",
++          "active":true
+         }
+       ]
+     }
+@@ -198,7 +204,8 @@
+           "backupIndex":[
+             0,
+             1,
+-            2
++            2,
++            3
+           ]
+         }
+       ],
+@@ -217,6 +224,11 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt5",
+           "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt6",
++          "active":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-lfa-topo1/rt1/step11/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step11/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..f7f99c2
--- /dev/null
@@ -0,0 +1,23 @@
+--- a/rt1/step10/show_ipv6_route.ref
++++ b/rt1/step11/show_ipv6_route.ref
+@@ -204,19 +204,13 @@
+           "backupIndex":[
+             0,
+             1,
+-            2,
+-            3
++            2
+           ]
+         }
+       ],
+       "backupNexthops":[
+         {
+           "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+           "interfaceName":"eth-rt4",
+           "active":true
+         },
diff --git a/tests/topotests/isis-lfa-topo1/rt1/step12/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step12/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..3b767f1
--- /dev/null
@@ -0,0 +1,107 @@
+--- a/rt1/step11/show_ipv6_route.ref
++++ b/rt1/step12/show_ipv6_route.ref
+@@ -15,9 +15,7 @@
+           "interfaceName":"eth-rt2",
+           "active":true,
+           "backupIndex":[
+-            0,
+-            1,
+-            2
++            0
+           ]
+         }
+       ],
+@@ -26,16 +24,6 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+           "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt6",
+-          "active":true
+         }
+       ]
+     }
+@@ -56,8 +44,7 @@
+           "interfaceName":"eth-rt3",
+           "active":true,
+           "backupIndex":[
+-            0,
+-            1
++            0
+           ]
+         }
+       ],
+@@ -66,11 +53,6 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+           "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+-          "active":true
+         }
+       ]
+     }
+@@ -120,10 +102,7 @@
+           "interfaceName":"eth-rt5",
+           "active":true,
+           "backupIndex":[
+-            0,
+-            1,
+-            2,
+-            3
++            0
+           ]
+         }
+       ],
+@@ -132,21 +111,6 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+           "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt4",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt6",
+-          "active":true
+         }
+       ]
+     }
+@@ -203,19 +167,13 @@
+           "active":true,
+           "backupIndex":[
+             0,
+-            1,
+-            2
++            1
+           ]
+         }
+       ],
+       "backupNexthops":[
+         {
+           "afi":"ipv6",
+-          "interfaceName":"eth-rt4",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+           "interfaceName":"eth-rt5",
+           "active":true
+         },
diff --git a/tests/topotests/isis-lfa-topo1/rt1/step13/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step13/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..504af5a
--- /dev/null
@@ -0,0 +1,45 @@
+--- a/rt1/step12/show_ipv6_route.ref
++++ b/rt1/step13/show_ipv6_route.ref
+@@ -131,8 +131,7 @@
+           "interfaceName":"eth-rt6",
+           "active":true,
+           "backupIndex":[
+-            0,
+-            1
++            0
+           ]
+         }
+       ],
+@@ -141,11 +140,6 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+           "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+-          "active":true
+         }
+       ]
+     }
+@@ -166,19 +160,13 @@
+           "interfaceName":"eth-rt2",
+           "active":true,
+           "backupIndex":[
+-            0,
+-            1
++            0
+           ]
+         }
+       ],
+       "backupNexthops":[
+         {
+           "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+           "interfaceName":"eth-rt6",
+           "active":true
+         }
diff --git a/tests/topotests/isis-lfa-topo1/rt1/step2/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step2/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..efc56d9
--- /dev/null
@@ -0,0 +1,164 @@
+--- a/rt1/step1/show_ipv6_route.ref
++++ b/rt1/step2/show_ipv6_route.ref
+@@ -13,28 +13,6 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0,
+-            1,
+-            2
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt6",
+           "active":true
+         }
+       ]
+@@ -54,22 +32,6 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true,
+-          "backupIndex":[
+-            0,
+-            1
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+           "active":true
+         }
+       ]
+@@ -89,16 +51,6 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt4",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+           "active":true
+         }
+       ]
+@@ -118,34 +70,6 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt5",
+-          "active":true,
+-          "backupIndex":[
+-            0,
+-            1,
+-            2,
+-            3
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt4",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt6",
+           "active":true
+         }
+       ]
+@@ -165,22 +89,6 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt6",
+-          "active":true,
+-          "backupIndex":[
+-            0,
+-            1
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+           "active":true
+         }
+       ]
+@@ -200,34 +108,6 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0,
+-            1,
+-            2,
+-            3
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt4",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt6",
+           "active":true
+         }
+       ]
diff --git a/tests/topotests/isis-lfa-topo1/rt1/step3/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step3/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..cafbe49
--- /dev/null
@@ -0,0 +1,164 @@
+--- a/rt1/step2/show_ipv6_route.ref
++++ b/rt1/step3/show_ipv6_route.ref
+@@ -13,6 +13,28 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
++          "active":true,
++          "backupIndex":[
++            0,
++            1,
++            2
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt5",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt6",
+           "active":true
+         }
+       ]
+@@ -32,6 +54,22 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
++          "active":true,
++          "backupIndex":[
++            0,
++            1
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt5",
+           "active":true
+         }
+       ]
+@@ -51,6 +89,16 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt4",
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt5",
+           "active":true
+         }
+       ]
+@@ -70,6 +118,34 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt5",
++          "active":true,
++          "backupIndex":[
++            0,
++            1,
++            2,
++            3
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt4",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt6",
+           "active":true
+         }
+       ]
+@@ -89,6 +165,22 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt6",
++          "active":true,
++          "backupIndex":[
++            0,
++            1
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt5",
+           "active":true
+         }
+       ]
+@@ -108,6 +200,34 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
++          "active":true,
++          "backupIndex":[
++            0,
++            1,
++            2,
++            3
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt4",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt5",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt6",
+           "active":true
+         }
+       ]
diff --git a/tests/topotests/isis-lfa-topo1/rt1/step4/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step4/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..47d8334
--- /dev/null
@@ -0,0 +1,142 @@
+--- a/rt1/step3/show_ipv6_route.ref
++++ b/rt1/step4/show_ipv6_route.ref
+@@ -15,9 +15,7 @@
+           "interfaceName":"eth-rt2",
+           "active":true,
+           "backupIndex":[
+-            0,
+-            1,
+-            2
++            0
+           ]
+         }
+       ],
+@@ -26,16 +24,6 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+           "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt6",
+-          "active":true
+         }
+       ]
+     }
+@@ -56,8 +44,7 @@
+           "interfaceName":"eth-rt3",
+           "active":true,
+           "backupIndex":[
+-            0,
+-            1
++            0
+           ]
+         }
+       ],
+@@ -66,11 +53,6 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+           "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+-          "active":true
+         }
+       ]
+     }
+@@ -120,10 +102,7 @@
+           "interfaceName":"eth-rt5",
+           "active":true,
+           "backupIndex":[
+-            0,
+-            1,
+-            2,
+-            3
++            0
+           ]
+         }
+       ],
+@@ -132,21 +111,6 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+           "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt4",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt6",
+-          "active":true
+         }
+       ]
+     }
+@@ -167,8 +131,7 @@
+           "interfaceName":"eth-rt6",
+           "active":true,
+           "backupIndex":[
+-            0,
+-            1
++            0
+           ]
+         }
+       ],
+@@ -177,11 +140,6 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+           "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+-          "active":true
+         }
+       ]
+     }
+@@ -202,10 +160,7 @@
+           "interfaceName":"eth-rt2",
+           "active":true,
+           "backupIndex":[
+-            0,
+-            1,
+-            2,
+-            3
++            0
+           ]
+         }
+       ],
+@@ -214,21 +169,6 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+           "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt4",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt6",
+-          "active":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-lfa-topo1/rt1/step5/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step5/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..b6a342d
--- /dev/null
@@ -0,0 +1,142 @@
+--- a/rt1/step4/show_ipv6_route.ref
++++ b/rt1/step5/show_ipv6_route.ref
+@@ -15,7 +15,9 @@
+           "interfaceName":"eth-rt2",
+           "active":true,
+           "backupIndex":[
+-            0
++            0,
++            1,
++            2
+           ]
+         }
+       ],
+@@ -24,6 +26,16 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+           "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt5",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt6",
++          "active":true
+         }
+       ]
+     }
+@@ -44,7 +56,8 @@
+           "interfaceName":"eth-rt3",
+           "active":true,
+           "backupIndex":[
+-            0
++            0,
++            1
+           ]
+         }
+       ],
+@@ -53,6 +66,11 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+           "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt5",
++          "active":true
+         }
+       ]
+     }
+@@ -102,7 +120,10 @@
+           "interfaceName":"eth-rt5",
+           "active":true,
+           "backupIndex":[
+-            0
++            0,
++            1,
++            2,
++            3
+           ]
+         }
+       ],
+@@ -111,6 +132,21 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+           "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt4",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt6",
++          "active":true
+         }
+       ]
+     }
+@@ -131,7 +167,8 @@
+           "interfaceName":"eth-rt6",
+           "active":true,
+           "backupIndex":[
+-            0
++            0,
++            1
+           ]
+         }
+       ],
+@@ -140,6 +177,11 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+           "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt5",
++          "active":true
+         }
+       ]
+     }
+@@ -160,7 +202,10 @@
+           "interfaceName":"eth-rt2",
+           "active":true,
+           "backupIndex":[
+-            0
++            0,
++            1,
++            2,
++            3
+           ]
+         }
+       ],
+@@ -169,6 +214,21 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+           "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt4",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt5",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt6",
++          "active":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-lfa-topo1/rt1/step6/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step6/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..fafa299
--- /dev/null
@@ -0,0 +1,164 @@
+--- a/rt1/step5/show_ipv6_route.ref
++++ b/rt1/step6/show_ipv6_route.ref
+@@ -13,28 +13,6 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0,
+-            1,
+-            2
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt6",
+           "active":true
+         }
+       ]
+@@ -54,22 +32,6 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true,
+-          "backupIndex":[
+-            0,
+-            1
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+           "active":true
+         }
+       ]
+@@ -89,16 +51,6 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt4",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+           "active":true
+         }
+       ]
+@@ -118,34 +70,6 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt5",
+-          "active":true,
+-          "backupIndex":[
+-            0,
+-            1,
+-            2,
+-            3
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt4",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt6",
+           "active":true
+         }
+       ]
+@@ -165,22 +89,6 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt6",
+-          "active":true,
+-          "backupIndex":[
+-            0,
+-            1
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+           "active":true
+         }
+       ]
+@@ -200,34 +108,6 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0,
+-            1,
+-            2,
+-            3
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt4",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt5",
+-          "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt6",
+           "active":true
+         }
+       ]
diff --git a/tests/topotests/isis-lfa-topo1/rt1/step7/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step7/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..1803e2c
--- /dev/null
@@ -0,0 +1,37 @@
+--- a/rt1/step6/show_ipv6_route.ref
++++ b/rt1/step7/show_ipv6_route.ref
+@@ -108,6 +108,34 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
++          "active":true,
++          "backupIndex":[
++            0,
++            1,
++            2,
++            3
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt4",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt5",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt6",
+           "active":true
+         }
+       ]
diff --git a/tests/topotests/isis-lfa-topo1/rt1/step8/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step8/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..306f725
--- /dev/null
@@ -0,0 +1,129 @@
+--- a/rt1/step7/show_ipv6_route.ref
++++ b/rt1/step8/show_ipv6_route.ref
+@@ -13,6 +13,28 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
++          "active":true,
++          "backupIndex":[
++            0,
++            1,
++            2
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt5",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt6",
+           "active":true
+         }
+       ]
+@@ -32,6 +54,22 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
++          "active":true,
++          "backupIndex":[
++            0,
++            1
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt5",
+           "active":true
+         }
+       ]
+@@ -51,6 +89,16 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt4",
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt5",
+           "active":true
+         }
+       ]
+@@ -70,6 +118,34 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt5",
++          "active":true,
++          "backupIndex":[
++            0,
++            1,
++            2,
++            3
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt4",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt6",
+           "active":true
+         }
+       ]
+@@ -89,6 +165,22 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt6",
++          "active":true,
++          "backupIndex":[
++            0,
++            1
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true
++        },
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt5",
+           "active":true
+         }
+       ]
diff --git a/tests/topotests/isis-lfa-topo1/rt1/step9/show_ipv6_route.ref.diff b/tests/topotests/isis-lfa-topo1/rt1/step9/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..3ffab46
--- /dev/null
@@ -0,0 +1,46 @@
+--- a/rt1/step8/show_ipv6_route.ref
++++ b/rt1/step9/show_ipv6_route.ref
+@@ -16,8 +16,7 @@
+           "active":true,
+           "backupIndex":[
+             0,
+-            1,
+-            2
++            1
+           ]
+         }
+       ],
+@@ -31,11 +30,6 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt5",
+           "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt6",
+-          "active":true
+         }
+       ]
+     }
+@@ -204,8 +198,7 @@
+           "backupIndex":[
+             0,
+             1,
+-            2,
+-            3
++            2
+           ]
+         }
+       ],
+@@ -224,11 +217,6 @@
+           "afi":"ipv6",
+           "interfaceName":"eth-rt5",
+           "active":true
+-        },
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt6",
+-          "active":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-lfa-topo1/rt1/zebra.conf b/tests/topotests/isis-lfa-topo1/rt1/zebra.conf
new file mode 100644 (file)
index 0000000..317f103
--- /dev/null
@@ -0,0 +1,16 @@
+log file zebra.log
+!
+hostname rt1
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 1.1.1.1/32
+ ipv6 address 2001:db8:1000::1/128
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-lfa-topo1/rt2/isisd.conf b/tests/topotests/isis-lfa-topo1/rt2/isisd.conf
new file mode 100644 (file)
index 0000000..39ff257
--- /dev/null
@@ -0,0 +1,39 @@
+password 1
+hostname rt2
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt3
+ ipv6 router isis 1
+ isis metric 5
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt7
+ ipv6 router isis 1
+ isis metric 5
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+router isis 1
+ net 49.0000.0000.0000.0002.00
+ is-type level-1
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-lfa-topo1/rt2/step1/show_ipv6_route.ref b/tests/topotests/isis-lfa-topo1/rt2/step1/show_ipv6_route.ref
new file mode 100644 (file)
index 0000000..036bfe1
--- /dev/null
@@ -0,0 +1,162 @@
+{
+  "2001:db8:1000::1\/128":[
+    {
+      "prefix":"2001:db8:1000::1\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::3\/128":[
+    {
+      "prefix":"2001:db8:1000::3\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":15,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::4\/128":[
+    {
+      "prefix":"2001:db8:1000::4\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        },
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::5\/128":[
+    {
+      "prefix":"2001:db8:1000::5\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":25,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::6\/128":[
+    {
+      "prefix":"2001:db8:1000::6\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":25,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::7\/128":[
+    {
+      "prefix":"2001:db8:1000::7\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":15,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/isis-lfa-topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-lfa-topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644 (file)
index 0000000..681c522
--- /dev/null
@@ -0,0 +1,63 @@
+{
+  "frr-interface:lib": {
+    "interface": [
+      {
+        "name": "eth-rt1",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0001",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt3",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0003",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt7",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0007",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-lfa-topo1/rt2/zebra.conf b/tests/topotests/isis-lfa-topo1/rt2/zebra.conf
new file mode 100644 (file)
index 0000000..9feaada
--- /dev/null
@@ -0,0 +1,16 @@
+log file zebra.log
+!
+hostname rt2
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 2.2.2.2/32
+ ipv6 address 2001:db8:1000::2/128
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-lfa-topo1/rt3/isisd.conf b/tests/topotests/isis-lfa-topo1/rt3/isisd.conf
new file mode 100644 (file)
index 0000000..8b0c7bd
--- /dev/null
@@ -0,0 +1,38 @@
+password 1
+hostname rt3
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt2
+ ipv6 router isis 1
+ isis metric 5
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt7
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+router isis 1
+ net 49.0000.0000.0000.0003.00
+ is-type level-1
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-lfa-topo1/rt3/step1/show_ipv6_route.ref b/tests/topotests/isis-lfa-topo1/rt3/step1/show_ipv6_route.ref
new file mode 100644 (file)
index 0000000..a1aab40
--- /dev/null
@@ -0,0 +1,188 @@
+{
+  "2001:db8:1000::1\/128":[
+    {
+      "prefix":"2001:db8:1000::1\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true,
+          "backupIndex":[
+            0,
+            1
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::2\/128":[
+    {
+      "prefix":"2001:db8:1000::2\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":15,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "backupIndex":[
+            0,
+            1
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::4\/128":[
+    {
+      "prefix":"2001:db8:1000::4\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true,
+          "backupIndex":[
+            0,
+            1
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::5\/128":[
+    {
+      "prefix":"2001:db8:1000::5\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        },
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::6\/128":[
+    {
+      "prefix":"2001:db8:1000::6\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        },
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        },
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::7\/128":[
+    {
+      "prefix":"2001:db8:1000::7\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        },
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/isis-lfa-topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-lfa-topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644 (file)
index 0000000..1495e32
--- /dev/null
@@ -0,0 +1,63 @@
+{
+  "frr-interface:lib": {
+    "interface": [
+      {
+        "name": "eth-rt1",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0001",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt2",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0002",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt7",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0007",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-lfa-topo1/rt3/zebra.conf b/tests/topotests/isis-lfa-topo1/rt3/zebra.conf
new file mode 100644 (file)
index 0000000..48d732e
--- /dev/null
@@ -0,0 +1,16 @@
+log file zebra.log
+!
+hostname rt3
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 3.3.3.3/32
+ ipv6 address 2001:db8:1000::3/128
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-lfa-topo1/rt4/isisd.conf b/tests/topotests/isis-lfa-topo1/rt4/isisd.conf
new file mode 100644 (file)
index 0000000..86edee6
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt4
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt7
+ ipv6 router isis 1
+ isis metric 15
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+router isis 1
+ net 49.0000.0000.0000.0004.00
+ is-type level-1
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-lfa-topo1/rt4/step1/show_ipv6_route.ref b/tests/topotests/isis-lfa-topo1/rt4/step1/show_ipv6_route.ref
new file mode 100644 (file)
index 0000000..6878e2f
--- /dev/null
@@ -0,0 +1,172 @@
+{
+  "2001:db8:1000::1\/128":[
+    {
+      "prefix":"2001:db8:1000::1\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::2\/128":[
+    {
+      "prefix":"2001:db8:1000::2\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        },
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::3\/128":[
+    {
+      "prefix":"2001:db8:1000::3\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::5\/128":[
+    {
+      "prefix":"2001:db8:1000::5\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":35,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::6\/128":[
+    {
+      "prefix":"2001:db8:1000::6\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::7\/128":[
+    {
+      "prefix":"2001:db8:1000::7\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":25,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/isis-lfa-topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-lfa-topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644 (file)
index 0000000..d8cd565
--- /dev/null
@@ -0,0 +1,44 @@
+{
+  "frr-interface:lib": {
+    "interface": [
+      {
+        "name": "eth-rt1",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0001",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt7",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0007",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-lfa-topo1/rt4/zebra.conf b/tests/topotests/isis-lfa-topo1/rt4/zebra.conf
new file mode 100644 (file)
index 0000000..bff1086
--- /dev/null
@@ -0,0 +1,16 @@
+log file zebra.log
+!
+hostname rt4
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 4.4.4.4/32
+ ipv6 address 2001:db8:1000::4/128
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-lfa-topo1/rt5/isisd.conf b/tests/topotests/isis-lfa-topo1/rt5/isisd.conf
new file mode 100644 (file)
index 0000000..7a7cfe5
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt5
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt1
+ ipv6 router isis 1
+ isis metric 20
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt7
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+router isis 1
+ net 49.0000.0000.0000.0005.00
+ is-type level-1
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-lfa-topo1/rt5/step1/show_ipv6_route.ref b/tests/topotests/isis-lfa-topo1/rt5/step1/show_ipv6_route.ref
new file mode 100644 (file)
index 0000000..f8181c7
--- /dev/null
@@ -0,0 +1,176 @@
+{
+  "2001:db8:1000::1\/128":[
+    {
+      "prefix":"2001:db8:1000::1\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::2\/128":[
+    {
+      "prefix":"2001:db8:1000::2\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":25,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::3\/128":[
+    {
+      "prefix":"2001:db8:1000::3\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::4\/128":[
+    {
+      "prefix":"2001:db8:1000::4\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":35,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::6\/128":[
+    {
+      "prefix":"2001:db8:1000::6\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::7\/128":[
+    {
+      "prefix":"2001:db8:1000::7\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/isis-lfa-topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-lfa-topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644 (file)
index 0000000..d8cd565
--- /dev/null
@@ -0,0 +1,44 @@
+{
+  "frr-interface:lib": {
+    "interface": [
+      {
+        "name": "eth-rt1",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0001",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt7",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0007",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-lfa-topo1/rt5/zebra.conf b/tests/topotests/isis-lfa-topo1/rt5/zebra.conf
new file mode 100644 (file)
index 0000000..ee1e46c
--- /dev/null
@@ -0,0 +1,16 @@
+log file zebra.log
+!
+hostname rt5
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 5.5.5.5/32
+ ipv6 address 2001:db8:1000::5/128
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-lfa-topo1/rt6/isisd.conf b/tests/topotests/isis-lfa-topo1/rt6/isisd.conf
new file mode 100644 (file)
index 0000000..20cb776
--- /dev/null
@@ -0,0 +1,31 @@
+password 1
+hostname rt6
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt7
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+router isis 1
+ net 49.0000.0000.0000.0006.00
+ is-type level-1
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-lfa-topo1/rt6/step1/show_ipv6_route.ref b/tests/topotests/isis-lfa-topo1/rt6/step1/show_ipv6_route.ref
new file mode 100644 (file)
index 0000000..e5f3c77
--- /dev/null
@@ -0,0 +1,172 @@
+{
+  "2001:db8:1000::1\/128":[
+    {
+      "prefix":"2001:db8:1000::1\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::2\/128":[
+    {
+      "prefix":"2001:db8:1000::2\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":25,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::3\/128":[
+    {
+      "prefix":"2001:db8:1000::3\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        },
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::4\/128":[
+    {
+      "prefix":"2001:db8:1000::4\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::5\/128":[
+    {
+      "prefix":"2001:db8:1000::5\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::7\/128":[
+    {
+      "prefix":"2001:db8:1000::7\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/isis-lfa-topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-lfa-topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644 (file)
index 0000000..d8cd565
--- /dev/null
@@ -0,0 +1,44 @@
+{
+  "frr-interface:lib": {
+    "interface": [
+      {
+        "name": "eth-rt1",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0001",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt7",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0007",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-lfa-topo1/rt6/zebra.conf b/tests/topotests/isis-lfa-topo1/rt6/zebra.conf
new file mode 100644 (file)
index 0000000..4108078
--- /dev/null
@@ -0,0 +1,16 @@
+log file zebra.log
+!
+hostname rt6
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 6.6.6.6/32
+ ipv6 address 2001:db8:1000::6/128
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-lfa-topo1/rt7/isisd.conf b/tests/topotests/isis-lfa-topo1/rt7/isisd.conf
new file mode 100644 (file)
index 0000000..713e6d3
--- /dev/null
@@ -0,0 +1,51 @@
+password 1
+hostname rt6
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt2
+ ipv6 router isis 1
+ isis metric 5
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt3
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt4
+ ipv6 router isis 1
+ isis metric 15
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt5
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+interface eth-rt6
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+ isis fast-reroute lfa
+!
+router isis 1
+ net 49.0000.0000.0000.0007.00
+ is-type level-1
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-lfa-topo1/rt7/step1/show_ipv6_route.ref b/tests/topotests/isis-lfa-topo1/rt7/step1/show_ipv6_route.ref
new file mode 100644 (file)
index 0000000..0dff15e
--- /dev/null
@@ -0,0 +1,186 @@
+{
+  "2001:db8:1000::1\/128":[
+    {
+      "prefix":"2001:db8:1000::1\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":25,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "backupIndex":[
+            0,
+            1,
+            2,
+            3
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt4",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt5",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::2\/128":[
+    {
+      "prefix":"2001:db8:1000::2\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":15,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::3\/128":[
+    {
+      "prefix":"2001:db8:1000::3\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        },
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::4\/128":[
+    {
+      "prefix":"2001:db8:1000::4\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":25,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt4",
+          "active":true,
+          "backupIndex":[
+            0,
+            1
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        },
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::5\/128":[
+    {
+      "prefix":"2001:db8:1000::5\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt5",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::6\/128":[
+    {
+      "prefix":"2001:db8:1000::6\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt4",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/isis-lfa-topo1/rt7/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-lfa-topo1/rt7/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644 (file)
index 0000000..d8a7c5a
--- /dev/null
@@ -0,0 +1,101 @@
+{
+  "frr-interface:lib": {
+    "interface": [
+      {
+        "name": "eth-rt2",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0002",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt3",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0003",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt4",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0004",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt5",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0005",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt6",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1",
+                  "neighbor-sysid": "0000.0000.0006",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-lfa-topo1/rt7/zebra.conf b/tests/topotests/isis-lfa-topo1/rt7/zebra.conf
new file mode 100644 (file)
index 0000000..353c9ef
--- /dev/null
@@ -0,0 +1,16 @@
+log file zebra.log
+!
+hostname rt7
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 7.7.7.7/32
+ ipv6 address 2001:db8:1000::7/128
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py b/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py
new file mode 100755 (executable)
index 0000000..a655b41
--- /dev/null
@@ -0,0 +1,636 @@
+#!/usr/bin/env python
+
+#
+# test_isis_tilfa_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_isis_lfa_topo1.py:
+
+                                       +---------+
+                                       |         |
+      +--------------------------------+   RT1   +-------------------------------+
+      |                  +-------------+         +-------------+                 |
+      |                  |             |         |             |                 |
+      |                  |             +----+----+             |                 |
+      |                  |                  |                  |20               |
+      |                  |                  |                  |                 |
+      |                  |                  |                  |                 |
+ +----+----+        +----+----+        +----+----+        +----+----+       +----+----+
+ |         |        |         |        |         |        |         |       |         |
+ |   RT2   |   5    |   RT3   |        |   RT4   |        |   RT5   |       |   RT6   |
+ |         +--------+         |        |         |        |         |       |         |
+ |         |        |         |        |         |        |         |       |         |
+ +----+----+        +----+----+        +----+----+        +----+----+       +----+----+
+      |                  |                  |                  |                 |
+      |                  |                  |15                |                 |
+      |5                 |                  |                  |                 |
+      |                  |             +----+----+             |                 |
+      |                  |             |         |             |                 |
+      |                  +-------------+   RT7   +-------------+                 |
+      +--------------------------------+         +-------------------------------+
+                                       |         |
+                                       +---------+
+"""
+
+import os
+import sys
+import pytest
+import json
+import re
+import tempfile
+from time import sleep
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+# Global multi-dimensional dictionary containing all expected outputs
+outputs = {}
+
+
+class TemplateTopo(Topo):
+    "Test topology builder"
+
+    def build(self, *_args, **_opts):
+        "Build function"
+        tgen = get_topogen(self)
+
+        #
+        # Define FRR Routers
+        #
+        for router in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
+            tgen.add_router(router)
+
+        #
+        # Define connections
+        #
+        switch = tgen.add_switch("s1")
+        switch.add_link(tgen.gears["rt1"], nodeif="eth-rt2")
+        switch.add_link(tgen.gears["rt2"], nodeif="eth-rt1")
+        switch = tgen.add_switch("s2")
+        switch.add_link(tgen.gears["rt2"], nodeif="eth-rt3")
+        switch.add_link(tgen.gears["rt3"], nodeif="eth-rt2")
+        switch = tgen.add_switch("s3")
+        switch.add_link(tgen.gears["rt1"], nodeif="eth-rt3")
+        switch.add_link(tgen.gears["rt3"], nodeif="eth-rt1")
+        switch = tgen.add_switch("s4")
+        switch.add_link(tgen.gears["rt1"], nodeif="eth-rt4")
+        switch.add_link(tgen.gears["rt4"], nodeif="eth-rt1")
+        switch = tgen.add_switch("s5")
+        switch.add_link(tgen.gears["rt1"], nodeif="eth-rt5")
+        switch.add_link(tgen.gears["rt5"], nodeif="eth-rt1")
+        switch = tgen.add_switch("s6")
+        switch.add_link(tgen.gears["rt1"], nodeif="eth-rt6")
+        switch.add_link(tgen.gears["rt6"], nodeif="eth-rt1")
+        switch = tgen.add_switch("s7")
+        switch.add_link(tgen.gears["rt2"], nodeif="eth-rt7")
+        switch.add_link(tgen.gears["rt7"], nodeif="eth-rt2")
+        switch = tgen.add_switch("s8")
+        switch.add_link(tgen.gears["rt3"], nodeif="eth-rt7")
+        switch.add_link(tgen.gears["rt7"], nodeif="eth-rt3")
+        switch = tgen.add_switch("s9")
+        switch.add_link(tgen.gears["rt4"], nodeif="eth-rt7")
+        switch.add_link(tgen.gears["rt7"], nodeif="eth-rt4")
+        switch = tgen.add_switch("s10")
+        switch.add_link(tgen.gears["rt5"], nodeif="eth-rt7")
+        switch.add_link(tgen.gears["rt7"], nodeif="eth-rt5")
+        switch = tgen.add_switch("s11")
+        switch.add_link(tgen.gears["rt6"], nodeif="eth-rt7")
+        switch.add_link(tgen.gears["rt7"], nodeif="eth-rt6")
+
+        #
+        # Populate multi-dimensional dictionary containing all expected outputs
+        #
+        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):
+                outputs[rname][step] = {}
+                for file in files:
+                    if step == 1:
+                        # Get snapshots relative to the expected initial network convergence
+                        filename = "{}/{}/step{}/{}".format(CWD, rname, step, file)
+                        outputs[rname][step][file] = open(filename).read()
+                    else:
+                        if rname != "rt1":
+                            continue
+                        if file == "show_yang_interface_isis_adjacencies.ref":
+                            continue
+
+                        # Get diff relative to the previous step
+                        filename = "{}/{}/step{}/{}.diff".format(CWD, rname, step, file)
+
+                        # Create temporary files in order to apply the diff
+                        f_in = tempfile.NamedTemporaryFile()
+                        f_in.write(outputs[rname][step - 1][file])
+                        f_in.flush()
+                        f_out = tempfile.NamedTemporaryFile()
+                        os.system(
+                            "patch -s -o %s %s %s" % (f_out.name, f_in.name, filename)
+                        )
+
+                        # Store the updated snapshot and remove the temporary files
+                        outputs[rname][step][file] = open(f_out.name).read()
+                        f_in.close()
+                        f_out.close()
+
+@pytest.mark.isis
+def setup_module(mod):
+    "Sets up the pytest environment"
+    tgen = Topogen(TemplateTopo, mod.__name__)
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+
+    # For all registered routers, load the zebra configuration file
+    for rname, router in router_list.iteritems():
+        router.load_config(
+            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
+        )
+
+    tgen.start_router()
+
+
+def teardown_module(mod):
+    "Teardown the pytest environment"
+    tgen = get_topogen()
+
+    # This function tears down the whole topology.
+    tgen.stop_topology()
+
+
+def router_compare_json_output(rname, command, reference):
+    "Compare router JSON output"
+
+    logger.info('Comparing router "%s" "%s" output', rname, command)
+
+    tgen = get_topogen()
+    expected = json.loads(reference)
+
+    # Run test function until we get an result. Wait at most 60 seconds.
+    test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
+    _, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
+    assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
+    assert diff is None, assertmsg
+
+
+#
+# Step 1
+#
+# Test initial network convergence
+#
+def test_isis_adjacencies_step1():
+    logger.info("Test (step 1): check IS-IS adjacencies")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
+        router_compare_json_output(
+            rname,
+            "show yang operational-data /frr-interface:lib isisd",
+            outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"],
+        )
+
+
+def test_rib_ipv6_step1():
+    logger.info("Test (step 1): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][1]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 2
+#
+# Action(s):
+# -Disable LFA protection on all interfaces
+#
+# Expected changes:
+# -rt1 should uninstall all backup nexthops from all routes
+#
+def test_rib_ipv6_step2():
+    logger.info("Test (step 2): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Disabling LFA protection on all rt1 interfaces")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute lfa"'
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt3" -c "no isis fast-reroute lfa"'
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt4" -c "no isis fast-reroute lfa"'
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt5" -c "no isis fast-reroute lfa"'
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt6" -c "no isis fast-reroute lfa"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][2]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 3
+#
+# Action(s):
+# -Re-enable LFA protection on all interfaces
+#
+# Expected changes:
+# -Revert changes from the previous step
+#
+def test_rib_ipv6_step3():
+    logger.info("Test (step 3): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Re-enabling LFA protection on all rt1 interfaces")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute lfa"'
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt3" -c "isis fast-reroute lfa"'
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt4" -c "isis fast-reroute lfa"'
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt5" -c "isis fast-reroute lfa"'
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt6" -c "isis fast-reroute lfa"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][3]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 4
+#
+# Action(s):
+# -Disable LFA load-sharing
+#
+# Expected changes:
+# -rt1 should use at most one backup nexthop for each route
+#
+def test_rib_ipv6_step4():
+    logger.info("Test (step 4): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Disabling LFA load-sharing on rt1")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute load-sharing disable"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][4]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 5
+#
+# Action(s):
+# -Re-enable LFA load-sharing
+#
+# Expected changes:
+# -Revert changes from the previous step
+#
+def test_rib_ipv6_step5():
+    logger.info("Test (step 5): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Re-enabling LFA load-sharing on rt1")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "no fast-reroute load-sharing disable"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][5]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 6
+#
+# Action(s):
+# -Limit backup computation to critical priority prefixes only
+#
+# Expected changes:
+# -rt1 should uninstall all backup nexthops from all routes
+#
+def test_rib_ipv6_step6():
+    logger.info("Test (step 6): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Limiting backup computation to critical priority prefixes only")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute priority-limit critical"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][6]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 7
+#
+# Action(s):
+# -Configure a prefix priority list to classify rt7's loopback as a
+#  critical-priority prefix
+#
+# Expected changes:
+# -rt1 should install backup nexthops for rt7's loopback route.
+#
+def test_rib_ipv6_step7():
+    logger.info("Test (step 7): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Configuring a prefix priority list")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "spf prefix-priority critical CRITICAL_DESTINATIONS"'
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "ipv6 access-list CRITICAL_DESTINATIONS seq 5 permit 2001:db8:1000::7/128"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][7]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 8
+#
+# Action(s):
+# -Revert previous changes related to prefix priorities
+#
+# Expected changes:
+# -Revert changes from the previous two steps
+#
+def test_rib_ipv6_step8():
+    logger.info("Test (step 8): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Reverting previous changes related to prefix priorities")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "no ipv6 access-list CRITICAL_DESTINATIONS seq 5 permit 2001:db8:1000::7/128"'
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "no fast-reroute priority-limit critical"'
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "no spf prefix-priority critical CRITICAL_DESTINATIONS"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][8]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 9
+#
+# Action(s):
+# -Exclude eth-rt6 from LFA computation for eth-rt2's failure
+#
+# Expected changes:
+# -Uninstall the eth-rt2 protecting backup nexthops that go through eth-rt6
+#
+def test_rib_ipv6_step9():
+    logger.info("Test (step 9): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Excluding eth-rt6 from LFA computation for eth-rt2's failure")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute lfa exclude interface eth-rt6"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][9]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 10
+#
+# Action(s):
+# -Remove exclusion of eth-rt6 from LFA computation for eth-rt2's failure
+#
+# Expected changes:
+# -Revert changes from the previous step
+#
+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)
+
+    logger.info(
+        "Removing exclusion of eth-rt6 from LFA computation for eth-rt2's failure"
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute lfa exclude interface eth-rt6"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname,
+            "show ipv6 route isis json",
+            outputs[rname][10]["show_ipv6_route.ref"],
+        )
+
+
+#
+# Step 11
+#
+# Action(s):
+# -Add LFA tiebreaker: prefer node protecting backup path
+#
+# Expected changes:
+# -rt1 should prefer backup nexthops that provide node protection
+#
+def test_rib_ipv6_step11():
+    logger.info("Test (step 11): 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("Adding LFA tiebreaker: prefer node protecting backup path")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker node-protecting index 10"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname,
+            "show ipv6 route isis json",
+            outputs[rname][11]["show_ipv6_route.ref"],
+        )
+
+
+#
+# Step 12
+#
+# Action(s):
+# -Add LFA tiebreaker: prefer backup path via downstream node
+#
+# Expected changes:
+# -rt1 should prefer backup nexthops that satisfy the downstream condition
+#
+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)
+
+    logger.info("Adding LFA tiebreaker: prefer backup path via downstream node")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker downstream index 20"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname,
+            "show ipv6 route isis json",
+            outputs[rname][12]["show_ipv6_route.ref"],
+        )
+
+
+#
+# Step 13
+#
+# Action(s):
+# -Add LFA tiebreaker: prefer backup path with lowest total metric
+#
+# Expected changes:
+# -rt1 should prefer backup nexthops that have the best metric
+#
+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)
+
+    logger.info("Adding LFA tiebreaker: prefer backup path with lowest total metric")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker lowest-backup-metric index 30"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname,
+            "show ipv6 route isis json",
+            outputs[rname][13]["show_ipv6_route.ref"],
+        )
+
+
+# Memory leak test template
+def test_memory_leak():
+    "Run the memory leak test and report results."
+    tgen = get_topogen()
+    if not tgen.is_memleak_enabled():
+        pytest.skip("Memory leak test/report is disabled")
+
+    tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/isis-rlfa-topo1/__init__.py b/tests/topotests/isis-rlfa-topo1/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt1/isisd.conf
new file mode 100644 (file)
index 0000000..a80f30d
--- /dev/null
@@ -0,0 +1,39 @@
+password 1
+hostname rt1
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt2
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+ isis fast-reroute lfa
+ isis fast-reroute remote-lfa tunnel mpls-ldp
+!
+interface eth-rt3
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+ isis fast-reroute lfa
+ isis fast-reroute remote-lfa tunnel mpls-ldp
+!
+ip prefix-list PLIST seq 5 permit 10.0.255.8/32
+!
+router isis 1
+ net 49.0000.0000.0000.0001.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+ fast-reroute remote-lfa prefix-list PLIST
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt1/ldpd.conf
new file mode 100644 (file)
index 0000000..f60fdb9
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt1
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.1
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.1
+  !
+  interface eth-rt2
+  interface eth-rt3
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::1
+  !
+  interface eth-rt2
+  interface eth-rt3
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step1/show_ip_route.ref b/tests/topotests/isis-rlfa-topo1/rt1/step1/show_ip_route.ref
new file mode 100644 (file)
index 0000000..680b31e
--- /dev/null
@@ -0,0 +1,235 @@
+{
+  "10.0.255.2\/32":[
+    {
+      "prefix":"10.0.255.2\/32",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.255.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "onLink":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "ip":"10.0.255.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "onLink":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "10.0.255.3\/32":[
+    {
+      "prefix":"10.0.255.3\/32",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.255.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "onLink":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "ip":"10.0.255.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "onLink":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "10.0.255.4\/32":[
+    {
+      "prefix":"10.0.255.4\/32",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.255.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "onLink":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "ip":"10.0.255.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "onLink":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "10.0.255.5\/32":[
+    {
+      "prefix":"10.0.255.5\/32",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.255.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "onLink":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "ip":"10.0.255.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "onLink":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "10.0.255.6\/32":[
+    {
+      "prefix":"10.0.255.6\/32",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.255.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "onLink":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "ip":"10.0.255.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "onLink":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "10.0.255.7\/32":[
+    {
+      "prefix":"10.0.255.7\/32",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.255.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "onLink":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "ip":"10.0.255.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "onLink":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "10.0.255.8\/32":[
+    {
+      "prefix":"10.0.255.8\/32",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":50,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.255.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "onLink":true
+        },
+        {
+          "fib":true,
+          "ip":"10.0.255.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "onLink":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step1/show_ipv6_route.ref b/tests/topotests/isis-rlfa-topo1/rt1/step1/show_ipv6_route.ref
new file mode 100644 (file)
index 0000000..c487d27
--- /dev/null
@@ -0,0 +1,207 @@
+{
+  "2001:db8::2\/128":[
+    {
+      "prefix":"2001:db8::2\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "2001:db8::3\/128":[
+    {
+      "prefix":"2001:db8::3\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "2001:db8::4\/128":[
+    {
+      "prefix":"2001:db8::4\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "2001:db8::5\/128":[
+    {
+      "prefix":"2001:db8::5\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "2001:db8::6\/128":[
+    {
+      "prefix":"2001:db8::6\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "2001:db8::7\/128":[
+    {
+      "prefix":"2001:db8::7\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "2001:db8::8\/128":[
+    {
+      "prefix":"2001:db8::8\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":50,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        },
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-rlfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644 (file)
index 0000000..3fe2b79
--- /dev/null
@@ -0,0 +1,44 @@
+{
+  "frr-interface:lib": {
+    "interface": [
+      {
+        "name": "eth-rt2",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1-2",
+                  "neighbor-sysid": "0000.0000.0002",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt3",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1-2",
+                  "neighbor-sysid": "0000.0000.0003",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step10/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step10/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..ef5707f
--- /dev/null
@@ -0,0 +1,68 @@
+--- a/rt1/step9/show_ip_route.ref
++++ b/rt1/step10/show_ip_route.ref
+@@ -15,7 +15,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -70,7 +83,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -125,7 +151,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step10/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step10/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..acd2ce0
--- /dev/null
@@ -0,0 +1,62 @@
+--- a/rt1/step9/show_ipv6_route.ref
++++ b/rt1/step10/show_ipv6_route.ref
+@@ -13,7 +13,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -62,7 +73,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -111,7 +133,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step2/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step2/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..f7f31ac
--- /dev/null
@@ -0,0 +1,134 @@
+--- a/rt1/step1/show_ip_route.ref
++++ b/rt1/step2/show_ip_route.ref
+@@ -15,20 +15,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -49,20 +36,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.2",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -83,20 +57,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -117,20 +78,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.2",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -151,20 +99,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -185,20 +120,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.2",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step2/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step2/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..e980031
--- /dev/null
@@ -0,0 +1,122 @@
+--- a/rt1/step1/show_ipv6_route.ref
++++ b/rt1/step2/show_ipv6_route.ref
+@@ -13,18 +13,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -43,18 +32,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -73,18 +51,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -103,18 +70,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -133,18 +89,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -163,18 +108,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step3/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step3/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..f3ed764
--- /dev/null
@@ -0,0 +1,134 @@
+--- a/rt1/step2/show_ip_route.ref
++++ b/rt1/step3/show_ip_route.ref
+@@ -15,7 +15,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -36,7 +49,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.2",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -57,7 +83,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -78,7 +117,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.2",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -99,7 +151,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -120,7 +185,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.2",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step3/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step3/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..57b0b1d
--- /dev/null
@@ -0,0 +1,122 @@
+--- a/rt1/step2/show_ipv6_route.ref
++++ b/rt1/step3/show_ipv6_route.ref
+@@ -13,7 +13,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -32,7 +43,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -51,7 +73,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -70,7 +103,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -89,7 +133,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -108,7 +163,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step4/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step4/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..107a0ba
--- /dev/null
@@ -0,0 +1,68 @@
+--- a/rt1/step3/show_ip_route.ref
++++ b/rt1/step4/show_ip_route.ref
+@@ -15,20 +15,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -83,20 +70,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -151,20 +125,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step4/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step4/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..9cf2408
--- /dev/null
@@ -0,0 +1,62 @@
+--- a/rt1/step3/show_ipv6_route.ref
++++ b/rt1/step4/show_ipv6_route.ref
+@@ -13,18 +13,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -73,18 +62,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -133,18 +111,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step5/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step5/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..0946950
--- /dev/null
@@ -0,0 +1,68 @@
+--- a/rt1/step4/show_ip_route.ref
++++ b/rt1/step5/show_ip_route.ref
+@@ -36,20 +36,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.2",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -91,20 +78,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.2",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -146,20 +120,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.2",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step5/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step5/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..70fb1a6
--- /dev/null
@@ -0,0 +1,62 @@
+--- a/rt1/step4/show_ipv6_route.ref
++++ b/rt1/step5/show_ipv6_route.ref
+@@ -32,18 +32,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -81,18 +70,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -130,18 +108,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step6/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step6/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..4e4a569
--- /dev/null
@@ -0,0 +1,134 @@
+--- a/rt1/step5/show_ip_route.ref
++++ b/rt1/step6/show_ip_route.ref
+@@ -15,7 +15,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -36,7 +49,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.2",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -57,7 +83,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -78,7 +117,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.2",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -99,7 +151,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -120,7 +185,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.2",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step6/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step6/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..c9ebb1e
--- /dev/null
@@ -0,0 +1,122 @@
+--- a/rt1/step5/show_ipv6_route.ref
++++ b/rt1/step6/show_ipv6_route.ref
+@@ -13,7 +13,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -32,7 +43,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -51,7 +73,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -70,7 +103,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -89,7 +133,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -108,7 +163,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step7/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step7/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step7/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step7/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step8/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step8/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step8/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step8/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step9/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step9/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..33eb657
--- /dev/null
@@ -0,0 +1,68 @@
+--- a/rt1/step8/show_ip_route.ref
++++ b/rt1/step9/show_ip_route.ref
+@@ -15,20 +15,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -83,20 +70,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -151,20 +125,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step9/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step9/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..7aaca33
--- /dev/null
@@ -0,0 +1,62 @@
+--- a/rt1/step8/show_ipv6_route.ref
++++ b/rt1/step9/show_ipv6_route.ref
+@@ -13,18 +13,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -73,18 +62,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -133,18 +111,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt1/zebra.conf
new file mode 100644 (file)
index 0000000..741fc2d
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt1
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.1/32
+ ipv6 address 2001:db8::1/128
+!
+interface eth-rt2
+ ip address 10.0.255.1/32
+!
+interface eth-rt3
+ ip address 10.0.255.1/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt2/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt2/isisd.conf
new file mode 100644 (file)
index 0000000..7b4c6c5
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt2
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt1
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+interface eth-rt4
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+router isis 1
+ net 49.0000.0000.0000.0002.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt2/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt2/ldpd.conf
new file mode 100644 (file)
index 0000000..0a815ef
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt2
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.2
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.2
+  !
+  interface eth-rt1
+  interface eth-rt4
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::2
+  !
+  interface eth-rt1
+  interface eth-rt4
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt2/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt2/zebra.conf
new file mode 100644 (file)
index 0000000..657c69b
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt2
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.2/32
+ ipv6 address 2001:db8::2/128
+!
+interface eth-rt1
+ ip address 10.0.255.2/32
+!
+interface eth-rt4
+ ip address 10.0.255.2/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt3/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt3/isisd.conf
new file mode 100644 (file)
index 0000000..17d58a9
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt3
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt1
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+interface eth-rt5
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+router isis 1
+ net 49.0000.0000.0000.0003.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt3/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt3/ldpd.conf
new file mode 100644 (file)
index 0000000..40f1f55
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt3
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.3
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.3
+  !
+  interface eth-rt1
+  interface eth-rt5
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::3
+  !
+  interface eth-rt1
+  interface eth-rt5
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt3/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt3/zebra.conf
new file mode 100644 (file)
index 0000000..86f5d28
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt3
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.3/32
+ ipv6 address 2001:db8::3/128
+!
+interface eth-rt1
+ ip address 10.0.255.3/32
+!
+interface eth-rt5
+ ip address 10.0.255.3/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt4/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt4/isisd.conf
new file mode 100644 (file)
index 0000000..1519fd4
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt4
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt2
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+interface eth-rt6
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+router isis 1
+ net 49.0000.0000.0000.0004.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt4/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt4/ldpd.conf
new file mode 100644 (file)
index 0000000..569ecf7
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt4
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.4
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.4
+  !
+  interface eth-rt2
+  interface eth-rt6
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::4
+  !
+  interface eth-rt2
+  interface eth-rt6
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt4/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt4/zebra.conf
new file mode 100644 (file)
index 0000000..1dd09bf
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt4
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.4/32
+ ipv6 address 2001:db8::4/128
+!
+interface eth-rt2
+ ip address 10.0.255.4/32
+!
+interface eth-rt6
+ ip address 10.0.255.4/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt5/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt5/isisd.conf
new file mode 100644 (file)
index 0000000..caf7477
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt5
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt3
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+interface eth-rt7
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+router isis 1
+ net 49.0000.0000.0000.0005.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt5/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt5/ldpd.conf
new file mode 100644 (file)
index 0000000..519c3d3
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt5
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.5
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.5
+  !
+  interface eth-rt3
+  interface eth-rt7
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::5
+  !
+  interface eth-rt3
+  interface eth-rt7
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt5/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt5/zebra.conf
new file mode 100644 (file)
index 0000000..7117a2a
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt5
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.5/32
+ ipv6 address 2001:db8::5/128
+!
+interface eth-rt3
+ ip address 10.0.255.5/32
+!
+interface eth-rt7
+ ip address 10.0.255.5/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt6/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt6/isisd.conf
new file mode 100644 (file)
index 0000000..cdf6267
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt6
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt4
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+interface eth-rt8
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+router isis 1
+ net 49.0000.0000.0000.0006.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt6/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt6/ldpd.conf
new file mode 100644 (file)
index 0000000..a5b7062
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt6
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.6
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.6
+  !
+  interface eth-rt4
+  interface eth-rt8
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::6
+  !
+  interface eth-rt4
+  interface eth-rt8
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt6/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt6/zebra.conf
new file mode 100644 (file)
index 0000000..c634487
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt6
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.6/32
+ ipv6 address 2001:db8::6/128
+!
+interface eth-rt4
+ ip address 10.0.255.6/32
+!
+interface eth-rt8
+ ip address 10.0.255.6/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt7/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt7/isisd.conf
new file mode 100644 (file)
index 0000000..8ab8fcb
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt7
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt5
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+interface eth-rt8
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+router isis 1
+ net 49.0000.0000.0000.0007.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt7/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt7/ldpd.conf
new file mode 100644 (file)
index 0000000..26d428c
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt7
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.7
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.7
+  !
+  interface eth-rt5
+  interface eth-rt8
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::7
+  !
+  interface eth-rt5
+  interface eth-rt8
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt7/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt7/zebra.conf
new file mode 100644 (file)
index 0000000..4c5e0f1
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt7
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.7/32
+ ipv6 address 2001:db8::7/128
+!
+interface eth-rt5
+ ip address 10.0.255.7/32
+!
+interface eth-rt8
+ ip address 10.0.255.7/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt8/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt8/isisd.conf
new file mode 100644 (file)
index 0000000..abdc6a5
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt8
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt6
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+interface eth-rt7
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+router isis 1
+ net 49.0000.0000.0000.0008.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt8/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt8/ldpd.conf
new file mode 100644 (file)
index 0000000..1629f82
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt8
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.8
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.8
+  !
+  interface eth-rt6
+  interface eth-rt7
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::8
+  !
+  interface eth-rt6
+  interface eth-rt7
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt8/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt8/zebra.conf
new file mode 100644 (file)
index 0000000..f3f10f6
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt8
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.8/32
+ ipv6 address 2001:db8::8/128
+!
+interface eth-rt6
+ ip address 10.0.255.8/32
+!
+interface eth-rt7
+ ip address 10.0.255.8/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py b/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py
new file mode 100755 (executable)
index 0000000..bb43e6b
--- /dev/null
@@ -0,0 +1,662 @@
+#!/usr/bin/env python
+
+#
+# test_isis_rlfa_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_isis_rlfa_topo1.py:
+
+ +---------+                     +---------+
+ |         |                     |         |
+ |   RT1   |                     |   RT2   |
+ |         +---------------------+         |
+ |         |                     |         |
+ +---+-----+                     +------+--+
+     |                                  |
+     |                                  |
+     |                                  |
+ +---+-----+                     +------+--+
+ |         |                     |         |
+ |   RT3   |                     |   RT4   |
+ |         |                     |         |
+ |         |                     |         |
+ +---+-----+                     +------+--+
+     |                                  |
+     |                                  |
+     |                                  |
+ +---+-----+                     +------+--+
+ |         |                     |         |
+ |   RT5   |                     |   RT6   |
+ |         |                     |         |
+ |         |                     |         |
+ +---+-----+                     +------+--+
+     |                                  |
+     |                                  |
+     |                                  |
+ +---+-----+                     +------+--+
+ |         |                     |         |
+ |   RT7   |                     |   RT8   |
+ |         +---------------------+         |
+ |         |                     |         |
+ +---------+                     +---------+
+"""
+
+import os
+import sys
+import pytest
+import json
+import re
+import tempfile
+from time import sleep
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+# Global multi-dimensional dictionary containing all expected outputs
+outputs = {}
+
+
+class TemplateTopo(Topo):
+    "Test topology builder"
+
+    def build(self, *_args, **_opts):
+        "Build function"
+        tgen = get_topogen(self)
+
+        #
+        # Define FRR Routers
+        #
+        for router in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7", "rt8"]:
+            tgen.add_router(router)
+
+        #
+        # Define connections
+        #
+        switch = tgen.add_switch("s1")
+        switch.add_link(tgen.gears["rt1"], nodeif="eth-rt2")
+        switch.add_link(tgen.gears["rt2"], nodeif="eth-rt1")
+        switch = tgen.add_switch("s2")
+        switch.add_link(tgen.gears["rt1"], nodeif="eth-rt3")
+        switch.add_link(tgen.gears["rt3"], nodeif="eth-rt1")
+        switch = tgen.add_switch("s3")
+        switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4")
+        switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2")
+        switch = tgen.add_switch("s4")
+        switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5")
+        switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3")
+        switch = tgen.add_switch("s5")
+        switch.add_link(tgen.gears["rt4"], nodeif="eth-rt6")
+        switch.add_link(tgen.gears["rt6"], nodeif="eth-rt4")
+        switch = tgen.add_switch("s6")
+        switch.add_link(tgen.gears["rt5"], nodeif="eth-rt7")
+        switch.add_link(tgen.gears["rt7"], nodeif="eth-rt5")
+        switch = tgen.add_switch("s7")
+        switch.add_link(tgen.gears["rt6"], nodeif="eth-rt8")
+        switch.add_link(tgen.gears["rt8"], nodeif="eth-rt6")
+        switch = tgen.add_switch("s8")
+        switch.add_link(tgen.gears["rt7"], nodeif="eth-rt8")
+        switch.add_link(tgen.gears["rt8"], nodeif="eth-rt7")
+
+        #
+        # Populate multi-dimensional dictionary containing all expected outputs
+        #
+        files = [
+            "show_ip_route.ref",
+            "show_ipv6_route.ref",
+            "show_yang_interface_isis_adjacencies.ref",
+        ]
+        for rname in ["rt1"]:
+            outputs[rname] = {}
+            for step in range(1, 10 + 1):
+                outputs[rname][step] = {}
+                for file in files:
+                    if step == 1:
+                        # Get snapshots relative to the expected initial network convergence
+                        filename = "{}/{}/step{}/{}".format(CWD, rname, step, file)
+                        outputs[rname][step][file] = open(filename).read()
+                    else:
+                        if file == "show_yang_interface_isis_adjacencies.ref":
+                            continue
+
+                        # Get diff relative to the previous step
+                        filename = "{}/{}/step{}/{}.diff".format(CWD, rname, step, file)
+
+                        # Create temporary files in order to apply the diff
+                        f_in = tempfile.NamedTemporaryFile()
+                        f_in.write(outputs[rname][step - 1][file])
+                        f_in.flush()
+                        f_out = tempfile.NamedTemporaryFile()
+                        os.system(
+                            "patch -s -o %s %s %s" % (f_out.name, f_in.name, filename)
+                        )
+
+                        # Store the updated snapshot and remove the temporary files
+                        outputs[rname][step][file] = open(f_out.name).read()
+                        f_in.close()
+                        f_out.close()
+
+@pytest.mark.isis
+def setup_module(mod):
+    "Sets up the pytest environment"
+    tgen = Topogen(TemplateTopo, mod.__name__)
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+
+    # For all registered routers, load the zebra configuration file
+    for rname, router in router_list.iteritems():
+        router.load_config(
+            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname))
+        )
+
+    tgen.start_router()
+
+
+def teardown_module(mod):
+    "Teardown the pytest environment"
+    tgen = get_topogen()
+
+    # This function tears down the whole topology.
+    tgen.stop_topology()
+
+
+def router_compare_json_output(rname, command, reference):
+    "Compare router JSON output"
+
+    logger.info('Comparing router "%s" "%s" output', rname, command)
+
+    tgen = get_topogen()
+    expected = json.loads(reference)
+
+    # Run test function until we get an result. Wait at most 60 seconds.
+    test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
+    _, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
+    assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
+    assert diff is None, assertmsg
+
+
+#
+# Step 1
+#
+# Test initial network convergence
+#
+def test_isis_adjacencies_step1():
+    logger.info("Test (step 1): check IS-IS adjacencies")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname,
+            "show yang operational-data /frr-interface:lib isisd",
+            outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"],
+        )
+
+
+def test_rib_ipv4_step1():
+    logger.info("Test (step 1): verify IPv4 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][1]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step1():
+    logger.info("Test (step 1): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][1]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 2
+#
+# Action(s):
+# -Configure rt8 (rt1's PQ router) to not accept targeted hello messages
+#
+# Expected changes:
+# -All rt1 backup routes should be uninstalled
+#
+def test_rib_ipv4_step2():
+    logger.info("Test (step 2): verify IPv4 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Configuring rt8 to not accept targeted hello messages")
+    tgen.net["rt8"].cmd(
+        'vtysh -c "conf t" -c "mpls ldp" -c "address-family ipv4" -c "no discovery targeted-hello accept"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][2]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step2():
+    logger.info("Test (step 2): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][2]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 3
+#
+# Action(s):
+# -Configure rt8 (rt1's PQ router) to accept targeted hello messages
+#
+# Expected changes:
+# -All rt1 previously uninstalled backup routes should be reinstalled
+#
+def test_rib_ipv4_step3():
+    logger.info("Test (step 3): verify IPv4 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Configuring rt8 to accept targeted hello messages")
+    tgen.net["rt8"].cmd(
+        'vtysh -c "conf t" -c "mpls ldp" -c "address-family ipv4" -c "discovery targeted-hello accept"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][3]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step3():
+    logger.info("Test (step 3): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][3]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 4
+#
+# Action(s):
+# -Disable RLFA on rt1's eth-rt2 interface
+#
+# Expected changes:
+# -All non-ECMP routes whose primary nexthop is eth-rt2 should lose their backup nexthops
+#
+def test_rib_ipv4_step4():
+    logger.info("Test (step 4): verify IPv4 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Disabling RLFA on rt1's eth-rt2 interface")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute remote-lfa tunnel mpls-ldp"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][4]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step4():
+    logger.info("Test (step 4): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][4]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 5
+#
+# Action(s):
+# -Disable RLFA on rt1's eth-rt3 interface
+#
+# Expected changes:
+# -All non-ECMP routes whose primary nexthop is eth-rt3 should lose their backup nexthops
+#
+def test_rib_ipv4_step5():
+    logger.info("Test (step 5): verify IPv4 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Disabling RLFA on rt1's eth-rt3 interface")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt3" -c "no isis fast-reroute remote-lfa tunnel mpls-ldp"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][5]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step5():
+    logger.info("Test (step 5): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][5]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 6
+#
+# Action(s):
+# -Re-enable RLFA on rt1's eth-rt2 and eth-rt3 interfaces
+#
+# Expected changes:
+# -Revert changes from the previous two steps (reinstall all backup routes)
+#
+def test_rib_ipv4_step6():
+    logger.info("Test (step 6): verify IPv4 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Re-enabling RLFA on rt1's eth-rt2 and eth-rt3 interfaces")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute remote-lfa tunnel mpls-ldp"'
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt3" -c "isis fast-reroute remote-lfa tunnel mpls-ldp"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][6]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step6():
+    logger.info("Test (step 6): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][6]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 7
+#
+# Action(s):
+# -Configure a PQ node prefix-list filter
+#
+# Expected changes:
+# -All backup routes should be uninstalled
+#
+def test_rib_ipv4_step7():
+    logger.info("Test (step 7): verify IPv4 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Configuring a PQ node prefix-list filter")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute remote-lfa prefix-list PLIST"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][7]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step7():
+    logger.info("Test (step 7): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][7]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 8
+#
+# Action(s):
+# -Configure a prefix-list allowing rt8 as a PQ node
+#
+# Expected changes:
+# -All backup routes should be installed again
+#
+def test_rib_ipv4_step8():
+    logger.info("Test (step 8): verify IPv4 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Configuring a prefix-list allowing rt8 as a PQ node")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "ip prefix-list PLIST seq 5 permit 10.0.255.8/32"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][8]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step8():
+    logger.info("Test (step 8): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][8]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 9
+#
+# Action(s):
+# -Change the maximum metric up to the PQ node to 30 on the eth-rt2 interface
+#
+# Expected changes:
+# -All non-ECMP routes whose primary nexthop is eth-rt2 should lose their backup nexthops
+#
+def test_rib_ipv4_step9():
+    logger.info("Test (step 9): verify IPv4 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info(
+        "Changing the maximum metric up to the PQ node to 30 on the eth-rt2 interface"
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute remote-lfa maximum-metric 30"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][9]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step9():
+    logger.info("Test (step 9): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][9]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 10
+#
+# Action(s):
+# -Change the maximum metric up to the PQ node to 40 on the eth-rt2 interface
+#
+# Expected changes:
+# -All non-ECMP routes whose primary nexthop is eth-rt2 should recover their backup nexthops
+#
+def test_rib_ipv4_step10():
+    logger.info("Test (step 10): verify IPv4 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info(
+        "Changing the maximum metric up to the PQ node to 40 on the eth-rt2 interface"
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute remote-lfa maximum-metric 40"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][10]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step10():
+    logger.info("Test (step 10): verify IPv6 RIB")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname,
+            "show ipv6 route isis json",
+            outputs[rname][10]["show_ipv6_route.ref"],
+        )
+
+
+# Memory leak test template
+def test_memory_leak():
+    "Run the memory leak test and report results."
+    tgen = get_topogen()
+    if not tgen.is_memleak_enabled():
+        pytest.skip("Memory leak test/report is disabled")
+
+    tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/isis-sr-te-topo1/dst/zebra.conf b/tests/topotests/isis-sr-te-topo1/dst/zebra.conf
new file mode 100644 (file)
index 0000000..e873ac8
--- /dev/null
@@ -0,0 +1,19 @@
+log file zebra.log
+!
+hostname dst
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 9.9.9.2/32
+ ipv6 address 2001:db8:1066::2/128
+!
+interface eth-rt6
+ ip address 10.0.11.2/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/bgpd.conf b/tests/topotests/isis-sr-te-topo1/rt1/bgpd.conf
new file mode 100644 (file)
index 0000000..efc0370
--- /dev/null
@@ -0,0 +1,16 @@
+log file bgpd.log
+!
+router bgp 1
+ bgp router-id 1.1.1.1
+ neighbor 6.6.6.6 remote-as 1
+ neighbor 6.6.6.6 update-source lo
+ !
+ address-family ipv4 unicast
+  redistribute static
+  neighbor 6.6.6.6 next-hop-self
+  neighbor 6.6.6.6 route-map SET_SR_POLICY in
+ exit-address-family
+!
+route-map SET_SR_POLICY permit 10
+ set sr-te color 1
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/isisd.conf b/tests/topotests/isis-sr-te-topo1/rt1/isisd.conf
new file mode 100644 (file)
index 0000000..70ae1b0
--- /dev/null
@@ -0,0 +1,30 @@
+password 1
+hostname rt1
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis sr-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-sw1
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0001.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing on
+ segment-routing global-block 16000 23999
+ segment-routing node-msd 8
+ segment-routing prefix 1.1.1.1/32 index 10
+ segment-routing prefix 2001:db8:1000::1/128 index 11
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/pathd.conf b/tests/topotests/isis-sr-te-topo1/rt1/pathd.conf
new file mode 100644 (file)
index 0000000..9119714
--- /dev/null
@@ -0,0 +1,21 @@
+log file pathd.log
+!
+hostname rt1
+!
+segment-routing
+ traffic-eng
+  segment-list default
+   index 10 mpls label 16050
+   index 20 mpls label 16060
+  !
+  segment-list test
+   index 10 mpls label 16020
+   index 20 mpls label 16040
+   index 30 mpls label 16060
+  !
+  policy color 1 endpoint 6.6.6.6
+   name default
+   binding-sid 1111
+  !
+ !
+!
\ No newline at end of file
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/step1/show_mpls_table_with_candidate.ref b/tests/topotests/isis-sr-te-topo1/rt1/step1/show_mpls_table_with_candidate.ref
new file mode 100644 (file)
index 0000000..d4b27d1
--- /dev/null
@@ -0,0 +1,91 @@
+{
+  "1111":{
+    "inLabel":1111,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR-TE",
+        "outLabel":16050,
+        "outLabelStack":[
+          16050,
+          16060
+        ],
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.3"
+      }
+    ]
+  },
+  "16020":{
+    "inLabel":16020,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16020,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.2"
+      }
+    ]
+  },
+  "16030":{
+    "inLabel":16030,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16030,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.3"
+      }
+    ]
+  },
+  "16040":{
+    "inLabel":16040,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16040,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.2"
+      }
+    ]
+  },
+  "16050":{
+    "inLabel":16050,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16050,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.3"
+      }
+    ]
+  },
+  "16060":{
+    "inLabel":16060,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16060,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.3"
+      },
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16060,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.2"
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/step1/show_mpls_table_without_candidate.ref b/tests/topotests/isis-sr-te-topo1/rt1/step1/show_mpls_table_without_candidate.ref
new file mode 100644 (file)
index 0000000..5fe58d0
--- /dev/null
@@ -0,0 +1,74 @@
+{
+  "16020":{
+    "inLabel":16020,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16020,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.2"
+      }
+    ]
+  },
+  "16030":{
+    "inLabel":16030,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16030,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.3"
+      }
+    ]
+  },
+  "16040":{
+    "inLabel":16040,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16040,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.2"
+      }
+    ]
+  },
+  "16050":{
+    "inLabel":16050,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16050,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.3"
+      }
+    ]
+  },
+  "16060":{
+    "inLabel":16060,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16060,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.3"
+      },
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16060,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.2"
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/step2/show_operational_data.ref b/tests/topotests/isis-sr-te-topo1/rt1/step2/show_operational_data.ref
new file mode 100644 (file)
index 0000000..4ef8d94
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "frr-pathd:pathd": {
+    "srte": {
+      "policy": [
+        {
+          "color": 1,
+          "endpoint": "6.6.6.6",
+          "is-operational": false
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/step2/show_operational_data_with_candidate.ref b/tests/topotests/isis-sr-te-topo1/rt1/step2/show_operational_data_with_candidate.ref
new file mode 100644 (file)
index 0000000..9b28f6a
--- /dev/null
@@ -0,0 +1,20 @@
+{
+  "frr-pathd:pathd": {
+    "srte": {
+      "policy": [
+        {
+          "color": 1,
+          "endpoint": "6.6.6.6",
+          "is-operational": true,
+          "candidate-path": [
+            {
+              "preference": 100,
+              "discriminator": "*",
+              "is-best-candidate-path": true
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/step3/show_operational_data_with_single_candidate.ref b/tests/topotests/isis-sr-te-topo1/rt1/step3/show_operational_data_with_single_candidate.ref
new file mode 100644 (file)
index 0000000..9b28f6a
--- /dev/null
@@ -0,0 +1,20 @@
+{
+  "frr-pathd:pathd": {
+    "srte": {
+      "policy": [
+        {
+          "color": 1,
+          "endpoint": "6.6.6.6",
+          "is-operational": true,
+          "candidate-path": [
+            {
+              "preference": 100,
+              "discriminator": "*",
+              "is-best-candidate-path": true
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/step3/show_operational_data_with_two_candidates.ref b/tests/topotests/isis-sr-te-topo1/rt1/step3/show_operational_data_with_two_candidates.ref
new file mode 100644 (file)
index 0000000..2491171
--- /dev/null
@@ -0,0 +1,25 @@
+{
+  "frr-pathd:pathd": {
+    "srte": {
+      "policy": [
+        {
+          "color": 1,
+          "endpoint": "6.6.6.6",
+          "is-operational": true,
+          "candidate-path": [
+            {
+              "preference": 100,
+              "discriminator": "*",
+              "is-best-candidate-path": false
+            },
+            {
+              "preference": 200,
+              "discriminator": "*",
+              "is-best-candidate-path": true
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/step4/show_mpls_table.ref b/tests/topotests/isis-sr-te-topo1/rt1/step4/show_mpls_table.ref
new file mode 100644 (file)
index 0000000..21f71f1
--- /dev/null
@@ -0,0 +1,20 @@
+{
+  "1111":{
+    "inLabel":1111,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR-TE",
+        "outLabel":16020,
+        "outLabelStack":[
+          16020,
+          16040,
+          16060
+        ],
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.2"
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/step4/show_mpls_table_add_segment.ref b/tests/topotests/isis-sr-te-topo1/rt1/step4/show_mpls_table_add_segment.ref
new file mode 100644 (file)
index 0000000..3635c89
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "1111":{
+    "inLabel":1111,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR-TE",
+        "outLabel":16020,
+        "outLabelStack":[
+          16020,
+          16040,
+          16050,
+          16060
+        ],
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.2"
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/step4/show_mpls_table_change_segment.ref b/tests/topotests/isis-sr-te-topo1/rt1/step4/show_mpls_table_change_segment.ref
new file mode 100644 (file)
index 0000000..5712d21
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "1111":{
+    "inLabel":1111,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR-TE",
+        "outLabel":16020,
+        "outLabelStack":[
+          16020,
+          16040,
+          16030,
+          16060
+        ],
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.1.2"
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/step5/show_ip_route_bgp_active_srte.ref b/tests/topotests/isis-sr-te-topo1/rt1/step5/show_ip_route_bgp_active_srte.ref
new file mode 100644 (file)
index 0000000..5a76246
--- /dev/null
@@ -0,0 +1,29 @@
+{
+  "9.9.9.2\/32":[
+    {
+      "prefix":"9.9.9.2\/32",
+      "protocol":"bgp",
+      "installed":true,
+      "nexthops":[
+        {
+          "ip":"6.6.6.6",
+          "afi":"ipv4",
+          "active":true,
+          "recursive":true,
+          "srteColor":1
+        },
+        {
+          "fib":true,
+          "ip":"10.0.1.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-sw1",
+          "active":true,
+          "labels":[
+            16050,
+            16060
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/step5/show_ip_route_bgp_inactive_srte.ref b/tests/topotests/isis-sr-te-topo1/rt1/step5/show_ip_route_bgp_inactive_srte.ref
new file mode 100644 (file)
index 0000000..09d5958
--- /dev/null
@@ -0,0 +1,38 @@
+{
+  "9.9.9.2\/32":[
+    {
+      "prefix":"9.9.9.2\/32",
+      "protocol":"bgp",
+      "installed":true,
+      "nexthops":[
+        {
+          "ip":"6.6.6.6",
+          "afi":"ipv4",
+          "active":true,
+          "recursive":true,
+          "srteColor":1
+        },
+        {
+          "fib":true,
+          "ip":"10.0.1.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-sw1",
+          "active":true,
+          "labels":[
+            16060
+          ]
+        },
+        {
+          "fib":true,
+          "ip":"10.0.1.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-sw1",
+          "active":true,
+          "labels":[
+            16060
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/step5/show_operational_data_active.ref b/tests/topotests/isis-sr-te-topo1/rt1/step5/show_operational_data_active.ref
new file mode 100644 (file)
index 0000000..e26039b
--- /dev/null
@@ -0,0 +1,20 @@
+{
+  "frr-pathd:pathd": {
+    "srte": {
+      "policy": [
+       {
+         "color": 1,
+         "endpoint": "6.6.6.6",
+         "is-operational": true,
+         "candidate-path": [
+           {
+             "preference": 100,
+             "discriminator": "*",
+             "is-best-candidate-path": true
+           }
+         ]
+       }
+     ]
+    }
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/step5/show_operational_data_inactive.ref b/tests/topotests/isis-sr-te-topo1/rt1/step5/show_operational_data_inactive.ref
new file mode 100644 (file)
index 0000000..01505c0
--- /dev/null
@@ -0,0 +1,20 @@
+{
+  "frr-pathd:pathd": {
+    "srte": {
+      "policy": [
+        {
+          "color": 1,
+          "endpoint": "6.6.6.6",
+          "is-operational": false,
+          "candidate-path": [
+            {
+              "preference": 100,
+              "discriminator": "*",
+              "is-best-candidate-path": true
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt1/zebra.conf b/tests/topotests/isis-sr-te-topo1/rt1/zebra.conf
new file mode 100644 (file)
index 0000000..9d71d30
--- /dev/null
@@ -0,0 +1,19 @@
+log file zebra.log
+!
+hostname rt1
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 1.1.1.1/32
+ ipv6 address 2001:db8:1000::1/128
+!
+interface eth-sw1
+ ip address 10.0.1.1/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt2/isisd.conf b/tests/topotests/isis-sr-te-topo1/rt2/isisd.conf
new file mode 100644 (file)
index 0000000..733f26b
--- /dev/null
@@ -0,0 +1,41 @@
+hostname rt2
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis sr-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-sw1
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+!
+interface eth-rt4-1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt4-2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0002.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing on
+ segment-routing global-block 16000 23999
+ segment-routing node-msd 8
+ segment-routing prefix 2.2.2.2/32 index 20 no-php-flag
+ segment-routing prefix 2001:db8:1000::2/128 index 21 no-php-flag
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt2/zebra.conf b/tests/topotests/isis-sr-te-topo1/rt2/zebra.conf
new file mode 100644 (file)
index 0000000..dcb0686
--- /dev/null
@@ -0,0 +1,25 @@
+log file zebra.log
+!
+hostname rt2
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 2.2.2.2/32
+ ipv6 address 2001:db8:1000::2/128
+!
+interface eth-sw1
+ ip address 10.0.1.2/24
+!
+interface eth-rt4-1
+ ip address 10.0.2.2/24
+!
+interface eth-rt4-2
+ ip address 10.0.3.2/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt3/isisd.conf b/tests/topotests/isis-sr-te-topo1/rt3/isisd.conf
new file mode 100644 (file)
index 0000000..2395906
--- /dev/null
@@ -0,0 +1,41 @@
+hostname rt3
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis sr-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-sw1
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+!
+interface eth-rt5-1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt5-2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0003.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing on
+ segment-routing global-block 16000 23999
+ segment-routing node-msd 8
+ segment-routing prefix 3.3.3.3/32 index 30 no-php-flag
+ segment-routing prefix 2001:db8:1000::3/128 index 31 no-php-flag
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt3/zebra.conf b/tests/topotests/isis-sr-te-topo1/rt3/zebra.conf
new file mode 100644 (file)
index 0000000..3254529
--- /dev/null
@@ -0,0 +1,25 @@
+log file zebra.log
+!
+hostname rt3
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 3.3.3.3/32
+ ipv6 address 2001:db8:1000::3/128
+!
+interface eth-sw1
+ ip address 10.0.1.3/24
+!
+interface eth-rt5-1
+ ip address 10.0.4.3/24
+!
+interface eth-rt5-2
+ ip address 10.0.5.3/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt4/isisd.conf b/tests/topotests/isis-sr-te-topo1/rt4/isisd.conf
new file mode 100644 (file)
index 0000000..07a7867
--- /dev/null
@@ -0,0 +1,48 @@
+hostname rt4
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis sr-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt2-1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt2-2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt5
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt6
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0004.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing on
+ segment-routing global-block 16000 23999
+ segment-routing node-msd 8
+ segment-routing prefix 4.4.4.4/32 index 40 no-php-flag
+ segment-routing prefix 2001:db8:1000::4/128 index 41 no-php-flag
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt4/zebra.conf b/tests/topotests/isis-sr-te-topo1/rt4/zebra.conf
new file mode 100644 (file)
index 0000000..4945897
--- /dev/null
@@ -0,0 +1,28 @@
+log file zebra.log
+!
+hostname rt4
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 4.4.4.4/32
+ ipv6 address 2001:db8:1000::4/128
+!
+interface eth-rt2-1
+ ip address 10.0.2.4/24
+!
+interface eth-rt2-2
+ ip address 10.0.3.4/24
+!
+interface eth-rt5
+ ip address 10.0.6.4/24
+!
+interface eth-rt6
+ ip address 10.0.7.4/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt5/isisd.conf b/tests/topotests/isis-sr-te-topo1/rt5/isisd.conf
new file mode 100644 (file)
index 0000000..b0fcded
--- /dev/null
@@ -0,0 +1,48 @@
+hostname rt5
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis sr-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt3-1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt3-2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt4
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt6
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0005.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing on
+ segment-routing global-block 16000 23999
+ segment-routing node-msd 8
+ segment-routing prefix 5.5.5.5/32 index 50 no-php-flag
+ segment-routing prefix 2001:db8:1000::5/128 index 51 no-php-flag
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt5/zebra.conf b/tests/topotests/isis-sr-te-topo1/rt5/zebra.conf
new file mode 100644 (file)
index 0000000..4cfea1a
--- /dev/null
@@ -0,0 +1,28 @@
+log file zebra.log
+!
+hostname rt5
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 5.5.5.5/32
+ ipv6 address 2001:db8:1000::5/128
+!
+interface eth-rt3-1
+ ip address 10.0.4.5/24
+!
+interface eth-rt3-2
+ ip address 10.0.5.5/24
+!
+interface eth-rt4
+ ip address 10.0.6.5/24
+!
+interface eth-rt6
+ ip address 10.0.8.5/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt6/bgpd.conf b/tests/topotests/isis-sr-te-topo1/rt6/bgpd.conf
new file mode 100644 (file)
index 0000000..e72ee52
--- /dev/null
@@ -0,0 +1,12 @@
+log file bgpd.log
+!
+router bgp 1
+ bgp router-id 6.6.6.6
+ neighbor 1.1.1.1 remote-as 1
+ neighbor 1.1.1.1 update-source lo
+ !
+ address-family ipv4 unicast
+  redistribute static
+  neighbor 1.1.1.1 next-hop-self
+ exit-address-family
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt6/isisd.conf b/tests/topotests/isis-sr-te-topo1/rt6/isisd.conf
new file mode 100644 (file)
index 0000000..3be24ad
--- /dev/null
@@ -0,0 +1,36 @@
+hostname rt6
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis sr-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt4
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt5
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0006.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing on
+ segment-routing global-block 16000 23999
+ segment-routing node-msd 8
+ segment-routing prefix 6.6.6.6/32 index 60
+ segment-routing prefix 2001:db8:1000::6/128 index 61
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt6/pathd.conf b/tests/topotests/isis-sr-te-topo1/rt6/pathd.conf
new file mode 100644 (file)
index 0000000..3bada71
--- /dev/null
@@ -0,0 +1,21 @@
+log file pathd.log
+!
+hostname rt6
+!
+segment-routing
+ traffic-eng
+  segment-list default
+   index 10 mpls label 16020
+   index 20 mpls label 16010
+  !
+  segment-list test
+   index 10 mpls label 16050
+   index 20 mpls label 16030
+   index 30 mpls label 16010
+  !
+  policy color 1 endpoint 1.1.1.1
+   name default
+   binding-sid 6666
+  !
+ !
+!
diff --git a/tests/topotests/isis-sr-te-topo1/rt6/step1/show_mpls_table_with_candidate.ref b/tests/topotests/isis-sr-te-topo1/rt6/step1/show_mpls_table_with_candidate.ref
new file mode 100644 (file)
index 0000000..2bb0003
--- /dev/null
@@ -0,0 +1,91 @@
+{
+  "6666":{
+    "inLabel":6666,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR-TE",
+        "outLabel":16020,
+        "outLabelStack":[
+          16020,
+          16010
+        ],
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.7.4"
+      }
+    ]
+  },
+  "16010": {
+      "inLabel": 16010,
+      "installed": true,
+      "nexthops": [
+          {
+              "distance": 150,
+              "installed": true,
+              "nexthop": "10.0.7.4",
+              "outLabel": 16010,
+              "type": "SR (IS-IS)"
+          },
+          {
+              "distance": 150,
+              "installed": true,
+              "nexthop": "10.0.8.5",
+              "outLabel": 16010,
+              "type": "SR (IS-IS)"
+          }
+      ]
+  },
+  "16020":{
+    "inLabel":16020,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16020,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.7.4"
+      }
+    ]
+  },
+  "16030":{
+    "inLabel":16030,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16030,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.8.5"
+      }
+    ]
+  },
+  "16040":{
+    "inLabel":16040,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16040,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.7.4"
+      }
+    ]
+  },
+  "16050":{
+    "inLabel":16050,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16050,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.8.5"
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt6/step1/show_mpls_table_without_candidate.ref b/tests/topotests/isis-sr-te-topo1/rt6/step1/show_mpls_table_without_candidate.ref
new file mode 100644 (file)
index 0000000..348f776
--- /dev/null
@@ -0,0 +1,74 @@
+{
+  "16010": {
+      "inLabel": 16010,
+      "installed": true,
+      "nexthops": [
+          {
+              "distance": 150,
+              "installed": true,
+              "nexthop": "10.0.7.4",
+              "outLabel": 16010,
+              "type": "SR (IS-IS)"
+          },
+          {
+              "distance": 150,
+              "installed": true,
+              "nexthop": "10.0.8.5",
+              "outLabel": 16010,
+              "type": "SR (IS-IS)"
+          }
+      ]
+  },
+  "16020":{
+    "inLabel":16020,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16020,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.7.4"
+      }
+    ]
+  },
+  "16030":{
+    "inLabel":16030,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16030,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.8.5"
+      }
+    ]
+  },
+  "16040":{
+    "inLabel":16040,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16040,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.7.4"
+      }
+    ]
+  },
+  "16050":{
+    "inLabel":16050,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR (IS-IS)",
+        "outLabel":16050,
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.8.5"
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt6/step2/show_operational_data.ref b/tests/topotests/isis-sr-te-topo1/rt6/step2/show_operational_data.ref
new file mode 100644 (file)
index 0000000..241c80b
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "frr-pathd:pathd": {
+    "srte": {
+        "policy": [
+        {
+          "color": 1,
+          "endpoint": "1.1.1.1",
+          "is-operational": false
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt6/step2/show_operational_data_with_candidate.ref b/tests/topotests/isis-sr-te-topo1/rt6/step2/show_operational_data_with_candidate.ref
new file mode 100644 (file)
index 0000000..20ea69e
--- /dev/null
@@ -0,0 +1,19 @@
+{
+  "frr-pathd:pathd": {
+    "srte": {
+      "policy": [
+        {
+          "color": 1,
+          "endpoint": "1.1.1.1",
+          "is-operational": true,
+          "candidate-path": [
+            {
+              "preference": 100,
+              "is-best-candidate-path": true
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt6/step3/show_operational_data_with_single_candidate.ref b/tests/topotests/isis-sr-te-topo1/rt6/step3/show_operational_data_with_single_candidate.ref
new file mode 100644 (file)
index 0000000..20ea69e
--- /dev/null
@@ -0,0 +1,19 @@
+{
+  "frr-pathd:pathd": {
+    "srte": {
+      "policy": [
+        {
+          "color": 1,
+          "endpoint": "1.1.1.1",
+          "is-operational": true,
+          "candidate-path": [
+            {
+              "preference": 100,
+              "is-best-candidate-path": true
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt6/step3/show_operational_data_with_two_candidates.ref b/tests/topotests/isis-sr-te-topo1/rt6/step3/show_operational_data_with_two_candidates.ref
new file mode 100644 (file)
index 0000000..10cafe9
--- /dev/null
@@ -0,0 +1,23 @@
+{
+  "frr-pathd:pathd": {
+    "srte": {
+      "policy": [
+        {
+          "color": 1,
+          "endpoint": "1.1.1.1",
+          "is-operational": true,
+          "candidate-path": [
+            {
+              "preference": 100,
+              "is-best-candidate-path": false
+            },
+            {
+              "preference": 200,
+              "is-best-candidate-path": true
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt6/step4/show_mpls_table.ref b/tests/topotests/isis-sr-te-topo1/rt6/step4/show_mpls_table.ref
new file mode 100644 (file)
index 0000000..95bf995
--- /dev/null
@@ -0,0 +1,20 @@
+{
+  "6666":{
+    "inLabel":6666,
+    "installed":true,
+    "nexthops":[
+      {
+        "type":"SR-TE",
+        "outLabel":16050,
+        "outLabelStack":[
+          16050,
+          16030,
+          16010
+        ],
+        "distance":150,
+        "installed":true,
+        "nexthop":"10.0.8.5"
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-sr-te-topo1/rt6/zebra.conf b/tests/topotests/isis-sr-te-topo1/rt6/zebra.conf
new file mode 100644 (file)
index 0000000..32c6e6c
--- /dev/null
@@ -0,0 +1,27 @@
+log file zebra.log
+!
+hostname rt6
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 6.6.6.6/32
+ ipv6 address 2001:db8:1000::6/128
+!
+interface eth-rt4
+ ip address 10.0.7.6/24
+!
+interface eth-rt5
+ ip address 10.0.8.6/24
+!
+interface eth-dst
+ ip address 10.0.11.1/24
+!
+ip forwarding
+!
+ip route 9.9.9.2/32 10.0.11.2
+!
+line vty
+!
diff --git a/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py b/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py
new file mode 100755 (executable)
index 0000000..bfd2f92
--- /dev/null
@@ -0,0 +1,532 @@
+#!/usr/bin/env python
+
+#
+# test_isis_sr_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_isis_sr_te_topo1.py:
+
+                         +---------+
+                         |         |
+                         |   RT1   |
+                         | 1.1.1.1 |
+                         |         |
+                         +---------+
+                              |eth-sw1
+                              |
+                              |
+                              |
+         +---------+          |          +---------+
+         |         |          |          |         |
+         |   RT2   |eth-sw1   |   eth-sw1|   RT3   |
+         | 2.2.2.2 +----------+----------+ 3.3.3.3 |
+         |         |     10.0.1.0/24     |         |
+         +---------+                     +---------+
+    eth-rt4-1|  |eth-rt4-2          eth-rt5-1|  |eth-rt5-2
+             |  |                            |  |
+  10.0.2.0/24|  |10.0.3.0/24      10.0.4.0/24|  |10.0.5.0/24
+             |  |                            |  |
+    eth-rt2-1|  |eth-rt2-2          eth-rt3-1|  |eth-rt3-2
+         +---------+                     +---------+
+         |         |                     |         |
+         |   RT4   |     10.0.6.0/24     |   RT5   |
+         | 4.4.4.4 +---------------------+ 5.5.5.5 |
+         |         |eth-rt5       eth-rt4|         |
+         +---------+                     +---------+
+       eth-rt6|                                |eth-rt6
+              |                                |
+   10.0.7.0/24|                                |10.0.8.0/24
+              |          +---------+           |
+              |          |         |           |
+              |          |   RT6   |           |
+              +----------+ 6.6.6.6 +-----------+
+                  eth-rt4|         |eth-rt5
+                         +---------+
+                              |eth-dst (.1)
+                              |
+                              |10.0.11.0/24
+                              |
+                              |eth-rt6 (.2)
+                         +---------+
+                         |         |
+                         |   DST   |
+                         | 9.9.9.2 |
+                         |         |
+                         +---------+
+
+"""
+
+import os
+import sys
+import pytest
+import json
+import re
+from time import sleep
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+class TemplateTopo(Topo):
+    "Test topology builder"
+    def build(self, *_args, **_opts):
+        "Build function"
+        tgen = get_topogen(self)
+
+        #
+        # Define FRR Routers
+        #
+        for router in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'dst']:
+            tgen.add_router(router)
+
+        #
+        # Define connections
+        #
+        switch = tgen.add_switch('s1')
+        switch.add_link(tgen.gears['rt1'], nodeif="eth-sw1")
+        switch.add_link(tgen.gears['rt2'], nodeif="eth-sw1")
+        switch.add_link(tgen.gears['rt3'], nodeif="eth-sw1")
+
+        switch = tgen.add_switch('s2')
+        switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-1")
+        switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-1")
+
+        switch = tgen.add_switch('s3')
+        switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-2")
+        switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-2")
+
+        switch = tgen.add_switch('s4')
+        switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-1")
+        switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-1")
+
+        switch = tgen.add_switch('s5')
+        switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-2")
+        switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-2")
+
+        switch = tgen.add_switch('s6')
+        switch.add_link(tgen.gears['rt4'], nodeif="eth-rt5")
+        switch.add_link(tgen.gears['rt5'], nodeif="eth-rt4")
+
+        switch = tgen.add_switch('s7')
+        switch.add_link(tgen.gears['rt4'], nodeif="eth-rt6")
+        switch.add_link(tgen.gears['rt6'], nodeif="eth-rt4")
+
+        switch = tgen.add_switch('s8')
+        switch.add_link(tgen.gears['rt5'], nodeif="eth-rt6")
+        switch.add_link(tgen.gears['rt6'], nodeif="eth-rt5")
+
+        switch = tgen.add_switch('s9')
+        switch.add_link(tgen.gears['rt6'], nodeif="eth-dst")
+        switch.add_link(tgen.gears['dst'], nodeif="eth-rt6")
+
+@pytest.mark.isis
+def setup_module(mod):
+    "Sets up the pytest environment"
+
+    tgen = Topogen(TemplateTopo, mod.__name__)
+
+    frrdir = tgen.config.get(tgen.CONFIG_SECTION, "frrdir")
+    if not os.path.isfile(os.path.join(frrdir, "pathd")):
+        pytest.skip("pathd daemon wasn't built")
+
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+
+    # For all registered routers, load the zebra configuration file
+    for rname, router in router_list.iteritems():
+        router.load_config(
+            TopoRouter.RD_ZEBRA,
+            os.path.join(CWD, '{}/zebra.conf'.format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_ISIS,
+            os.path.join(CWD, '{}/isisd.conf'.format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_PATH,
+            os.path.join(CWD, '{}/pathd.conf'.format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_BGP,
+            os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+        )
+
+    tgen.start_router()
+
+def teardown_module(mod):
+    "Teardown the pytest environment"
+    tgen = get_topogen()
+
+    # This function tears down the whole topology.
+    tgen.stop_topology()
+
+def setup_testcase(msg):
+    logger.info(msg)
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    return tgen
+
+def print_cmd_result(rname, command):
+    print(get_topogen().gears[rname].vtysh_cmd(command, isjson=False))
+
+def compare_json_test(router, command, reference, exact):
+    output = router.vtysh_cmd(command, isjson=True)
+    result = topotest.json_cmp(output, reference)
+
+    # Note: topotest.json_cmp() just checks on inclusion of keys.
+    # For exact matching also compare the other way around.
+    if not result and exact:
+       return topotest.json_cmp(reference, output)
+    else:
+       return result
+
+def cmp_json_output(rname, command, reference, exact=False):
+    "Compare router JSON output"
+
+    logger.info('Comparing router "%s" "%s" output', rname, command)
+
+    tgen = get_topogen()
+    filename = '{}/{}/{}'.format(CWD, rname, reference)
+    expected = json.loads(open(filename).read())
+
+    # Run test function until we get an result. Wait at most 60 seconds.
+    test_func = partial(compare_json_test,
+        tgen.gears[rname], command, expected, exact)
+    _, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
+    assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
+    assert diff is None, assertmsg
+
+def cmp_json_output_exact(rname, command, reference):
+    return cmp_json_output(rname, command, reference, True)
+
+def add_candidate_path(rname, endpoint, pref, name, segment_list='default'):
+    get_topogen().net[rname].cmd(''' \
+        vtysh -c "conf t" \
+              -c "segment-routing" \
+              -c "traffic-eng" \
+              -c "policy color 1 endpoint ''' + endpoint + '''" \
+              -c "candidate-path preference ''' + str(pref) + ''' name ''' + name + ''' explicit segment-list ''' + segment_list + '''"''')
+
+def delete_candidate_path(rname, endpoint, pref):
+    get_topogen().net[rname].cmd(''' \
+        vtysh -c "conf t" \
+              -c "segment-routing" \
+              -c "traffic-eng" \
+              -c "policy color 1 endpoint ''' + endpoint + '''" \
+              -c "no candidate-path preference ''' + str(pref) + '''"''')
+
+def add_segment(rname, name, index, label):
+    get_topogen().net[rname].cmd(''' \
+        vtysh -c "conf t" \
+              -c "segment-routing" \
+              -c "traffic-eng" \
+              -c "segment-list ''' + name + '''" \
+              -c "index ''' + str(index) + ''' mpls label ''' + str(label) + '''"''')
+
+def delete_segment(rname, name, index):
+    get_topogen().net[rname].cmd(''' \
+        vtysh -c "conf t" \
+              -c "segment-routing" \
+              -c "traffic-eng" \
+              -c "segment-list ''' + name + '''" \
+              -c "no index ''' + str(index) + '''"''')
+
+def create_sr_policy(rname, endpoint, bsid):
+    get_topogen().net[rname].cmd(''' \
+        vtysh -c "conf t" \
+              -c "segment-routing" \
+              -c "traffic-eng" \
+              -c "policy color 1 endpoint ''' + endpoint + '''" \
+              -c "name default" \
+              -c "binding-sid ''' + str(bsid) + '''"''')
+
+def delete_sr_policy(rname, endpoint):
+    get_topogen().net[rname].cmd(''' \
+        vtysh -c "conf t" \
+              -c "segment-routing" \
+              -c "traffic-eng" \
+              -c "no policy color 1 endpoint ''' + endpoint + '''"''')
+
+def create_prefix_sid(rname, prefix, sid):
+    get_topogen().net[rname].cmd(''' \
+        vtysh -c "conf t" \
+              -c "router isis 1" \
+              -c "segment-routing prefix ''' + prefix + " index " + str(sid) + '''"''')
+
+def delete_prefix_sid(rname, prefix):
+    get_topogen().net[rname].cmd(''' \
+        vtysh -c "conf t" \
+              -c "router isis 1" \
+              -c "no segment-routing prefix "''' + prefix)
+
+#
+# Step 1
+#
+# Checking the MPLS table using a single SR Policy and a single Candidate Path
+#
+def test_srte_init_step1():
+    setup_testcase("Test (step 1): wait for IS-IS convergence / label distribution")
+
+    for rname in ['rt1', 'rt6']:
+        cmp_json_output(rname,
+                        "show mpls table json",
+                        "step1/show_mpls_table_without_candidate.ref")
+
+def test_srte_add_candidate_check_mpls_table_step1():
+    setup_testcase("Test (step 1): check MPLS table regarding the added Candidate Path")
+
+    for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
+        add_candidate_path(rname, endpoint, 100, 'default')
+        cmp_json_output(rname,
+                        "show mpls table json",
+                        "step1/show_mpls_table_with_candidate.ref")
+        delete_candidate_path(rname, endpoint, 100)
+
+def test_srte_reinstall_sr_policy_check_mpls_table_step1():
+    setup_testcase("Test (step 1): check MPLS table after the SR Policy was removed and reinstalled")
+
+    for rname, endpoint, bsid in [('rt1', '6.6.6.6', 1111), ('rt6', '1.1.1.1', 6666)]:
+        add_candidate_path(rname, endpoint, 100, 'default')
+        delete_sr_policy(rname, endpoint)
+        cmp_json_output(rname,
+                        "show mpls table json",
+                        "step1/show_mpls_table_without_candidate.ref")
+        create_sr_policy(rname, endpoint, bsid)
+        add_candidate_path(rname, endpoint, 100, 'default')
+        cmp_json_output(rname,
+                        "show mpls table json",
+                        "step1/show_mpls_table_with_candidate.ref")
+        delete_candidate_path(rname, endpoint, 100)
+
+#
+# Step 2
+#
+# Checking pathd operational data using a single SR Policy and a single Candidate Path
+#
+def test_srte_bare_policy_step2():
+    setup_testcase("Test (step 2): bare SR Policy should not be operational")
+
+    for rname in ['rt1', 'rt6']:
+        cmp_json_output_exact(rname,
+                              "show yang operational-data /frr-pathd:pathd pathd",
+                              "step2/show_operational_data.ref")
+
+def test_srte_add_candidate_check_operational_data_step2():
+    setup_testcase("Test (step 2): add single Candidate Path, SR Policy should be operational")
+
+    for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
+        add_candidate_path(rname, endpoint, 100, 'default')
+        cmp_json_output(rname,
+                        "show yang operational-data /frr-pathd:pathd pathd",
+                        "step2/show_operational_data_with_candidate.ref")
+
+def test_srte_config_remove_candidate_check_operational_data_step2():
+    setup_testcase("Test (step 2): remove single Candidate Path, SR Policy should not be operational anymore")
+
+    for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
+        delete_candidate_path(rname, endpoint, 100)
+        cmp_json_output_exact(rname,
+                              "show yang operational-data /frr-pathd:pathd pathd",
+                              "step2/show_operational_data.ref")
+
+#
+# Step 3
+#
+# Testing the Candidate Path selection
+#
+def test_srte_add_two_candidates_step3():
+    setup_testcase("Test (step 3): second Candidate Path has higher Priority")
+
+    for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
+        for pref, cand_name in [('100', 'first'), ('200', 'second')]:
+            add_candidate_path(rname, endpoint, pref, cand_name)
+        cmp_json_output(rname,
+                        "show yang operational-data /frr-pathd:pathd pathd",
+                        "step3/show_operational_data_with_two_candidates.ref")
+
+    # cleanup
+    for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
+        for pref in ['100', '200']:
+            delete_candidate_path(rname, endpoint, pref)
+
+def test_srte_add_two_candidates_with_reverse_priority_step3():
+    setup_testcase("Test (step 3): second Candidate Path has lower Priority")
+
+    # Use reversed priorities here
+    for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
+        for pref, cand_name in [('200', 'first'), ('100', 'second')]:
+            add_candidate_path(rname, endpoint, pref, cand_name)
+        cmp_json_output(rname,
+                        "show yang operational-data /frr-pathd:pathd pathd",
+                        "step3/show_operational_data_with_two_candidates.ref")
+
+    # cleanup
+    for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
+        for pref in ['100', '200']:
+            delete_candidate_path(rname, endpoint, pref)
+
+def test_srte_remove_best_candidate_step3():
+    setup_testcase("Test (step 3): delete the Candidate Path with higher priority")
+
+    for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
+        for pref, cand_name in [('100', 'first'), ('200', 'second')]:
+            add_candidate_path(rname, endpoint, pref, cand_name)
+
+    # Delete candidate with higher priority
+    for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
+        delete_candidate_path(rname, endpoint, 200)
+
+    # Candidate with lower priority should get active now
+    for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
+        cmp_json_output(rname,
+                        "show yang operational-data /frr-pathd:pathd pathd",
+                        "step3/show_operational_data_with_single_candidate.ref")
+        # cleanup
+        delete_candidate_path(rname, endpoint, 100)
+
+#
+# Step 4
+#
+# Checking MPLS table with a single SR Policy and a Candidate Path with different Segment Lists and other modifications
+#
+def test_srte_change_segment_list_check_mpls_table_step4():
+    setup_testcase("Test (step 4): check MPLS table for changed Segment List")
+
+    for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]:
+        add_candidate_path(rname, endpoint, 100, 'default')
+       # now change the segment list name
+        add_candidate_path(rname, endpoint, 100, 'default', 'test')
+        cmp_json_output(rname,
+                        "show mpls table json",
+                        "step4/show_mpls_table.ref")
+        delete_candidate_path(rname, endpoint, 100)
+
+def test_srte_segment_list_add_segment_check_mpls_table_step4():
+    setup_testcase("Test (step 4): check MPLS table for added (then changed and finally deleted) segment")
+
+    add_candidate_path('rt1', '6.6.6.6', 100, 'default', 'test')
+
+    # first add a new segment
+    add_segment('rt1', 'test', 25, 16050)
+    cmp_json_output('rt1',
+                    "show mpls table json",
+                    "step4/show_mpls_table_add_segment.ref")
+
+    # ... then change it ...
+    add_segment('rt1', 'test', 25, 16030)
+    cmp_json_output('rt1',
+                    "show mpls table json",
+                    "step4/show_mpls_table_change_segment.ref")
+
+    # ... and finally delete it
+    delete_segment('rt1', 'test', 25)
+    cmp_json_output('rt1',
+                    "show mpls table json",
+                    "step4/show_mpls_table.ref")
+    delete_candidate_path('rt1', '6.6.6.6', 100)
+
+#
+# Step 5
+#
+# Checking the nexthop using a single SR Policy and a Candidate Path with configured route-map
+#
+def test_srte_route_map_with_sr_policy_check_nextop_step5():
+    setup_testcase("Test (step 5): recursive nexthop learned through BGP neighbour should be aligned with SR Policy from route-map")
+
+    # (re-)build the SR Policy two times to ensure that reinstalling still works
+    for i in [1,2]:
+        cmp_json_output('rt1',
+                        "show ip route bgp json",
+                        "step5/show_ip_route_bgp_inactive_srte.ref")
+
+        delete_sr_policy('rt1', '6.6.6.6')
+        cmp_json_output('rt1',
+                        "show ip route bgp json",
+                        "step5/show_ip_route_bgp_inactive_srte.ref")
+
+        create_sr_policy('rt1', '6.6.6.6', 1111)
+        cmp_json_output('rt1',
+                        "show ip route bgp json",
+                        "step5/show_ip_route_bgp_inactive_srte.ref")
+
+        add_candidate_path('rt1', '6.6.6.6', 100, 'default')
+        cmp_json_output('rt1',
+                        "show ip route bgp json",
+                        "step5/show_ip_route_bgp_active_srte.ref")
+
+        delete_candidate_path('rt1', '6.6.6.6', 100)
+
+def test_srte_route_map_with_sr_policy_reinstall_prefix_sid_check_nextop_step5():
+    setup_testcase("Test (step 5): remove and re-install prefix SID on fist path element and check SR Policy activity")
+
+    # first add a candidate path so the SR Policy is active
+    add_candidate_path('rt1', '6.6.6.6', 100, 'default')
+    cmp_json_output('rt1',
+                    "show yang operational-data /frr-pathd:pathd pathd",
+                    "step5/show_operational_data_active.ref")
+
+    # delete prefix SID from first element of the configured path and check
+    # if the SR Policy is inactive since the label can't be resolved anymore
+    delete_prefix_sid('rt5', "5.5.5.5/32")
+    cmp_json_output('rt1',
+                    "show yang operational-data /frr-pathd:pathd pathd",
+                    "step5/show_operational_data_inactive.ref")
+    cmp_json_output('rt1',
+                    "show ip route bgp json",
+                    "step5/show_ip_route_bgp_inactive_srte.ref")
+
+    # re-create the prefix SID and check if the SR Policy is active
+    create_prefix_sid('rt5', "5.5.5.5/32", 50)
+    cmp_json_output('rt1',
+                    "show yang operational-data /frr-pathd:pathd pathd",
+                    "step5/show_operational_data_active.ref")
+    cmp_json_output('rt1',
+                    "show ip route bgp json",
+                    "step5/show_ip_route_bgp_active_srte.ref")
+
+# Memory leak test template
+def test_memory_leak():
+    "Run the memory leak test and report results."
+    tgen = get_topogen()
+    if not tgen.is_memleak_enabled():
+        pytest.skip('Memory leak test/report is disabled')
+
+    tgen.report_memory_leaks()
+
+if __name__ == '__main__':
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index 387d3b43d76a844da421eafbaa57d07add143846..b7d52cecca7a56517b708c519f8a90817175c9ba 100644 (file)
       ]
     }
   ],
-  "10.0.2.0\/24":[
-    {
-      "prefix":"10.0.2.0\/24",
-      "protocol":"isis",
-      "distance":115,
-      "metric":20,
-      "nexthops":[
-        {
-          "ip":"10.0.2.4",
-          "afi":"ipv4",
-          "interfaceName":"eth-rt4-1"
-        },
-        {
-          "ip":"10.0.3.4",
-          "afi":"ipv4",
-          "interfaceName":"eth-rt4-2",
-          "active":true
-        }
-      ]
-    }
-  ],
   "10.0.3.0\/24":[
     {
       "prefix":"10.0.3.0\/24",
index 4dc0dd7cacac06df5a195be8f02e8b0fe1cae8cc..f2a54bf9586970c20724f263dcdce2886328f70b 100644 (file)
       ]
     }
   ],
-  "10.0.7.0\/24":[
-    {
-      "prefix":"10.0.7.0\/24",
-      "protocol":"isis",
-      "distance":115,
-      "metric":20,
-      "nexthops":[
-        {
-          "ip":"10.0.7.6",
-          "afi":"ipv4",
-          "interfaceName":"eth-rt6"
-        }
-      ]
-    }
-  ],
   "10.0.8.0\/24":[
     {
       "prefix":"10.0.8.0\/24",
index 620f5eac67adf3c27d8d3eeb6d7763712c47cf67..29f47824826fb7ead774946e4f6470fb29d57ef0 100644 (file)
       ]
     }
   ],
-  "10.0.6.0\/24":[
-    {
-      "prefix":"10.0.6.0\/24",
-      "protocol":"isis",
-      "distance":115,
-      "metric":20,
-      "nexthops":[
-        {
-          "ip":"10.0.6.4",
-          "afi":"ipv4",
-          "interfaceName":"eth-rt4"
-        }
-      ]
-    }
-  ],
   "10.0.7.0\/24":[
     {
       "prefix":"10.0.7.0\/24",
index 19cdf9d89672ac58494688daa45d82b9ebc5e170..dc61b8641033b1f748955a6276334902b2b96c4a 100644 (file)
       ]
     }
   ],
-  "10.0.6.0\/24":[
-    {
-      "prefix":"10.0.6.0\/24",
-      "protocol":"isis",
-      "distance":115,
-      "metric":20,
-      "nexthops":[
-        {
-          "ip":"10.0.6.4",
-          "afi":"ipv4",
-          "interfaceName":"eth-rt4"
-        }
-      ]
-    }
-  ],
   "10.0.7.0\/24":[
     {
       "prefix":"10.0.7.0\/24",
index 48b5e6491eadafeb92f5164e6e45bfb3e90bc320..2d983c43b62dbbd2c4603e26b39d2c5746d5294f 100644 (file)
       ]
     }
   ],
-  "10.0.6.0\/24":[
-    {
-      "prefix":"10.0.6.0\/24",
-      "protocol":"isis",
-      "distance":115,
-      "metric":20,
-      "nexthops":[
-        {
-          "ip":"10.0.6.4",
-          "afi":"ipv4",
-          "interfaceName":"eth-rt4"
-        }
-      ]
-    }
-  ],
   "10.0.7.0\/24":[
     {
       "prefix":"10.0.7.0\/24",
index 156beef0f1017d0a773d5d718f2817764aac7ccf..0a64db60f648365e6191d7a0d3c21158160a374b 100644 (file)
       ]
     }
   ],
-  "10.0.6.0\/24":[
-    {
-      "prefix":"10.0.6.0\/24",
-      "protocol":"isis",
-      "distance":115,
-      "metric":20,
-      "nexthops":[
-        {
-          "ip":"10.0.6.4",
-          "afi":"ipv4",
-          "interfaceName":"eth-rt4"
-        }
-      ]
-    }
-  ],
   "10.0.7.0\/24":[
     {
       "prefix":"10.0.7.0\/24",
index dba5e8d8a2d79cac9646b869ca921fa8dc56da14..88485477e3b499820358145ca4f4021bded62477 100644 (file)
       ]
     }
   ],
-  "10.0.6.0\/24":[
-    {
-      "prefix":"10.0.6.0\/24",
-      "protocol":"isis",
-      "distance":115,
-      "metric":20,
-      "nexthops":[
-        {
-          "ip":"10.0.6.4",
-          "afi":"ipv4",
-          "interfaceName":"eth-rt4"
-        }
-      ]
-    }
-  ],
   "10.0.7.0\/24":[
     {
       "prefix":"10.0.7.0\/24",
index 156beef0f1017d0a773d5d718f2817764aac7ccf..0a64db60f648365e6191d7a0d3c21158160a374b 100644 (file)
       ]
     }
   ],
-  "10.0.6.0\/24":[
-    {
-      "prefix":"10.0.6.0\/24",
-      "protocol":"isis",
-      "distance":115,
-      "metric":20,
-      "nexthops":[
-        {
-          "ip":"10.0.6.4",
-          "afi":"ipv4",
-          "interfaceName":"eth-rt4"
-        }
-      ]
-    }
-  ],
   "10.0.7.0\/24":[
     {
       "prefix":"10.0.7.0\/24",
index ece747bdac0fa4aa1a2d452d9880e2e952fd1812..769bc4d31e00f0f7a9fa50932449a64532eceb66 100644 (file)
       ]
     }
   ],
-  "10.0.6.0\/24":[
-    {
-      "prefix":"10.0.6.0\/24",
-      "protocol":"isis",
-      "distance":115,
-      "metric":20,
-      "nexthops":[
-        {
-          "ip":"10.0.6.4",
-          "afi":"ipv4",
-          "interfaceName":"eth-rt4"
-        }
-      ]
-    }
-  ],
   "10.0.7.0\/24":[
     {
       "prefix":"10.0.7.0\/24",
index 156beef0f1017d0a773d5d718f2817764aac7ccf..0a64db60f648365e6191d7a0d3c21158160a374b 100644 (file)
       ]
     }
   ],
-  "10.0.6.0\/24":[
-    {
-      "prefix":"10.0.6.0\/24",
-      "protocol":"isis",
-      "distance":115,
-      "metric":20,
-      "nexthops":[
-        {
-          "ip":"10.0.6.4",
-          "afi":"ipv4",
-          "interfaceName":"eth-rt4"
-        }
-      ]
-    }
-  ],
   "10.0.7.0\/24":[
     {
       "prefix":"10.0.7.0\/24",
index 90588c6708d533a122b40a70eebf9d68d1f43e20..34cbf68b214eb00dba2bea1251199fb002632641 100644 (file)
       ]
     }
   ],
-  "10.0.6.0\/24":[
-    {
-      "prefix":"10.0.6.0\/24",
-      "protocol":"isis",
-      "distance":115,
-      "metric":20,
-      "nexthops":[
-        {
-          "ip":"10.0.6.4",
-          "afi":"ipv4",
-          "interfaceName":"eth-rt4"
-        }
-      ]
-    }
-  ],
   "10.0.7.0\/24":[
     {
       "prefix":"10.0.7.0\/24",
index 34eb6d90f69aa1087996ba56b4502a856ade3592..63be3f78aa9fd818594d98faae7f6d0172160a2d 100644 (file)
@@ -134,7 +134,7 @@ class TemplateTopo(Topo):
         switch.add_link(tgen.gears["rt5"], nodeif="eth-rt6")
         switch.add_link(tgen.gears["rt6"], nodeif="eth-rt5")
 
-
+@pytest.mark.isis
 def setup_module(mod):
     "Sets up the pytest environment"
     tgen = Topogen(TemplateTopo, mod.__name__)
index e3ed7c20b2fffa0045ff53f58b64110266c3289e..aa0357d7500062c835811bc9e2d3d5586691065e 100644 (file)
         "type":"SR (IS-IS)",
         "outLabel":16060,
         "installed":true,
-        "nexthop":"10.0.1.2"
+        "nexthop":"10.0.1.3"
       },
       {
         "type":"SR (IS-IS)",
         "outLabel":16060,
         "installed":true,
-        "nexthop":"10.0.1.3"
+        "nexthop":"10.0.1.2"
       }
     ]
   },
index 1a9307ddb99f7d4bdd7aabab7083c84c0c95c896..10b336f5b812d86c90f3ea82adc270ce7239b663 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step3/show_ip_route.ref        2020-09-25 17:48:05.062911204 -0300
-+++ rt1/step4/show_ip_route.ref        2020-09-25 17:49:01.563647190 -0300
+--- a/rt1/step3/show_ip_route.ref
++++ b/rt1/step4/show_ip_route.ref
 @@ -60,10 +60,7 @@
            "ip":"10.0.1.2",
            "afi":"ipv4",
index f5036aeda82c15efe7d8f742f9dc7d1d52fd0692..904aaa1ce2a1cf9b1716591cfb94b5b6513b5a32 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step3/show_ipv6_route.ref      2020-09-25 17:48:06.358928078 -0300
-+++ rt1/step4/show_ipv6_route.ref      2020-09-25 17:49:02.791663194 -0300
+--- a/rt1/step3/show_ipv6_route.ref
++++ b/rt1/step4/show_ipv6_route.ref
 @@ -57,10 +57,7 @@
            "fib":true,
            "afi":"ipv6",
index 30c612b5449bf5f9f64eadcfbbfd5c5acc0fad59..d7d875313105b80e9857f311582638c8222cbdd0 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step3/show_mpls_table.ref      2020-09-25 17:48:03.782894539 -0300
-+++ rt1/step4/show_mpls_table.ref      2020-09-25 17:49:00.343631290 -0300
+--- a/rt1/step3/show_mpls_table.ref
++++ b/rt1/step4/show_mpls_table.ref
 @@ -47,30 +47,6 @@
        }
      ]
index 79a452ef69f8c5ee0c4325ce1d8956241714638a..b583fa97bde2dea1a987d2f9d67935569deab3dd 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step4/show_ip_route.ref        2020-09-25 17:49:01.563647190 -0300
-+++ rt1/step5/show_ip_route.ref        2020-09-25 17:50:12.144567593 -0300
+--- a/rt1/step4/show_ip_route.ref
++++ b/rt1/step5/show_ip_route.ref
 @@ -60,7 +60,10 @@
            "ip":"10.0.1.2",
            "afi":"ipv4",
index 805266aaaa920f2a0cbf1ed5a2f70334bcbc160c..d608abec982080cb2104eccd49f00eb6724841d9 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step4/show_ipv6_route.ref      2020-09-25 17:49:02.791663194 -0300
-+++ rt1/step5/show_ipv6_route.ref      2020-09-25 17:50:13.428584346 -0300
+--- a/rt1/step4/show_ipv6_route.ref
++++ b/rt1/step5/show_ipv6_route.ref
 @@ -57,7 +57,10 @@
            "fib":true,
            "afi":"ipv6",
index d7ab66ee189b0710cbd6fcfa081bdfd40f5e1045..b5161fcd55ba20de15bb6f2b59e6547b41f22f5d 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step4/show_mpls_table.ref      2020-09-25 17:49:00.343631290 -0300
-+++ rt1/step5/show_mpls_table.ref      2020-09-25 17:50:10.868550944 -0300
+--- a/rt1/step4/show_mpls_table.ref
++++ b/rt1/step5/show_mpls_table.ref
 @@ -47,6 +47,30 @@
        }
      ]
index 9aa0cd2e39ae493a2878eaab8204256d453d85a9..726aed514fe2e74cb68e36a5e65738f075351261 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step6/show_ip_route.ref        2020-09-25 17:51:15.105389461 -0300
-+++ rt1/step7/show_ip_route.ref        2020-09-25 17:52:02.014002243 -0300
+--- a/rt1/step6/show_ip_route.ref
++++ b/rt1/step7/show_ip_route.ref
 @@ -83,10 +83,7 @@
            "ip":"10.0.1.3",
            "afi":"ipv4",
index 52fd7caf915b7579477b41656744c637c6248b0a..2049f6fa190aeaf735cf88e03ec9436aa7d22cdd 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step6/show_ipv6_route.ref      2020-09-25 17:51:16.345405655 -0300
-+++ rt1/step7/show_ipv6_route.ref      2020-09-25 17:52:03.230018133 -0300
+--- a/rt1/step6/show_ipv6_route.ref
++++ b/rt1/step7/show_ipv6_route.ref
 @@ -79,10 +79,7 @@
            "fib":true,
            "afi":"ipv6",
index 53332be5691323ea3f077c8c7646f92140b08a43..22301ba1ff876401b40ab369c7c2c7b3436deb72 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step6/show_mpls_table.ref      2020-09-25 17:51:13.861373215 -0300
-+++ rt1/step7/show_mpls_table.ref      2020-09-25 17:52:00.769985988 -0300
+--- a/rt1/step6/show_mpls_table.ref
++++ b/rt1/step7/show_mpls_table.ref
 @@ -71,30 +71,6 @@
        }
      ]
index af9f72e718afb4b3a24d01a81c94b3578b9739bc..4a1d4805a4e76a62059ae1e5db953cb43c9bb2df 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step7/show_ip_route.ref        2020-09-25 17:52:02.014002243 -0300
-+++ rt1/step8/show_ip_route.ref        2020-09-25 17:53:20.003021800 -0300
+--- a/rt1/step7/show_ip_route.ref
++++ b/rt1/step8/show_ip_route.ref
 @@ -83,7 +83,10 @@
            "ip":"10.0.1.3",
            "afi":"ipv4",
index b733b33ed9d9bfb00dbcafe1447f307c1b668605..eaece74e48b655d16ed5dbacaecfee5503344ae4 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step7/show_ipv6_route.ref      2020-09-25 17:52:03.230018133 -0300
-+++ rt1/step8/show_ipv6_route.ref      2020-09-25 17:53:21.239037966 -0300
+--- a/rt1/step7/show_ipv6_route.ref
++++ b/rt1/step8/show_ipv6_route.ref
 @@ -79,7 +79,10 @@
            "fib":true,
            "afi":"ipv6",
index b6f8c962f0fc7f8e6855af0fc8e75189c3242f52..46c17de01915e9f25dde42d698f00f1d327c4bf1 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step7/show_mpls_table.ref      2020-09-25 17:52:00.769985988 -0300
-+++ rt1/step8/show_mpls_table.ref      2020-09-25 17:53:18.671004379 -0300
+--- a/rt1/step7/show_mpls_table.ref
++++ b/rt1/step8/show_mpls_table.ref
 @@ -71,6 +71,30 @@
        }
      ]
index 1d963415571ccb262bc2e74f9bc5b4b3eeedc7c8..06efdc96ce596be5beb8e15a4b5c89e5bddb711e 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step8/show_ip_route.ref        2020-09-25 17:53:20.003021800 -0300
-+++ rt1/step9/show_ip_route.ref        2020-09-25 17:54:37.700038367 -0300
+--- a/rt1/step8/show_ip_route.ref
++++ b/rt1/step9/show_ip_route.ref
 @@ -85,7 +85,7 @@
            "interfaceName":"eth-sw1",
            "active":true,
index 232b823ac2bcc5c18da9bd360b78b824c8c7993c..a58f2d447cd6d128c46eb0ae79488e48960a6528 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step8/show_ipv6_route.ref      2020-09-25 17:53:21.239037966 -0300
-+++ rt1/step9/show_ipv6_route.ref      2020-09-25 17:54:38.912054230 -0300
+--- a/rt1/step8/show_ipv6_route.ref
++++ b/rt1/step9/show_ipv6_route.ref
 @@ -81,7 +81,7 @@
            "interfaceName":"eth-sw1",
            "active":true,
index 7f0d50f5f2263a6add1f74935622a20dbbab9675..c0a1ac592b51ee211ae260535667a082a6def8a1 100644 (file)
@@ -1,5 +1,5 @@
---- rt1/step8/show_mpls_table.ref      2020-09-25 17:53:18.671004379 -0300
-+++ rt1/step9/show_mpls_table.ref      2020-09-25 17:54:36.428021718 -0300
+--- a/rt1/step8/show_mpls_table.ref
++++ b/rt1/step9/show_mpls_table.ref
 @@ -71,30 +71,6 @@
        }
      ]
index 23e07b7cdad329c08e3d1b73dda0037306e936b4..7e1ccd10a2b7453983a8826dd41a22701c64ade2 100644 (file)
           "ip":"10.0.1.3",
           "afi":"ipv4",
           "interfaceName":"eth-sw1",
-          "active":true
+          "active":true,
+          "labels":[
+            16060
+          ]
         }
       ]
     }
index d9bd04ef30f5dc228f99f8e37030546460f3dfa8..6d31f6f26b8b4b2fce5446a44909971c865507fe 100644 (file)
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt4-2",
+          "interfaceName":"eth-rt4-1",
           "active":true,
           "backupIndex":[
             0
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt4-1",
+          "interfaceName":"eth-rt4-2",
           "active":true,
           "backupIndex":[
             0
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-sw1",
+          "interfaceName":"eth-rt4-1",
           "active":true,
           "labels":[
             16051
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt4-2",
+          "interfaceName":"eth-sw1",
           "active":true,
           "labels":[
             16051
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt4-1",
+          "interfaceName":"eth-rt4-2",
           "active":true,
           "labels":[
             16051
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt4-2",
+          "interfaceName":"eth-rt4-1",
           "active":true,
           "backupIndex":[
             0
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt4-1",
+          "interfaceName":"eth-rt4-2",
           "active":true,
           "backupIndex":[
             0
         {
           "afi":"ipv6",
           "interfaceName":"eth-sw1",
-          "active":true
+          "active":true,
+          "labels":[
+            16061
+          ]
         }
       ]
     }
index cd2f879593a0015ce8b20a5f1cd80cc739d36eb2..b9b906a31d9cede95b03b277c91691892526caed 100644 (file)
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16060,
         "nexthop":"10.0.1.3"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16061,
         "interface":"eth-sw1"
       }
     ]
index 22b896f6840e5678c83cc15d34b29ec57b501210..90e0895639b2008559dea9086a35ca00c8f61dd0 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step1/show_ip_route.ref        2020-09-25 17:46:27.537642781 -0300
-+++ rt2/step2/show_ip_route.ref        2020-09-25 17:46:57.306029668 -0300
+--- a/rt2/step1/show_ip_route.ref
++++ b/rt2/step2/show_ip_route.ref
 @@ -15,36 +15,10 @@
            "afi":"ipv4",
            "interfaceName":"eth-sw1",
@@ -74,7 +74,7 @@
        ]
      }
    ],
-@@ -248,40 +196,12 @@
+@@ -251,40 +199,12 @@
          {
            "ip":"10.0.1.1",
            "afi":"ipv4",
          }
        ]
      }
-@@ -377,24 +297,6 @@
+@@ -380,24 +300,6 @@
            "ip":"10.0.1.3",
            "afi":"ipv4",
            "interfaceName":"eth-sw1",
            "active":true
          }
        ]
-@@ -415,24 +317,6 @@
+@@ -418,24 +320,6 @@
            "ip":"10.0.1.3",
            "afi":"ipv4",
            "interfaceName":"eth-sw1",
index 08c7d2b1fcc8ff2116c5cf68151f45b0e8eba62b..2d19f20f633f91fdd63ab405ead73d00cf79870d 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step1/show_ipv6_route.ref      2020-09-25 17:46:28.865660035 -0300
-+++ rt2/step2/show_ipv6_route.ref      2020-09-25 17:46:58.514045373 -0300
+--- a/rt2/step1/show_ipv6_route.ref
++++ b/rt2/step2/show_ipv6_route.ref
 @@ -14,34 +14,10 @@
            "afi":"ipv6",
            "interfaceName":"eth-sw1",
index 4feb927156ad2ffa1b19d704285e71cef2b6d9c4..01fc74a60b75297cb72982e1456aa06d3f89bfbc 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step1/show_mpls_table.ref      2020-09-25 17:46:26.261626203 -0300
-+++ rt2/step2/show_mpls_table.ref      2020-09-25 17:46:56.086013807 -0300
+--- a/rt2/step1/show_mpls_table.ref
++++ b/rt2/step2/show_mpls_table.ref
 @@ -7,23 +7,7 @@
          "type":"SR (IS-IS)",
          "outLabel":3,
index af1cebc76da0c658b09cc8340c7cae3244967399..d93f0362291085a41c445b8a3900a13d53ba9d4d 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step2/show_ip_route.ref        2020-09-25 17:46:57.306029668 -0300
-+++ rt2/step3/show_ip_route.ref        2020-09-25 17:48:05.274913964 -0300
+--- a/rt2/step2/show_ip_route.ref
++++ b/rt2/step3/show_ip_route.ref
 @@ -15,10 +15,36 @@
            "afi":"ipv4",
            "interfaceName":"eth-sw1",
@@ -74,7 +74,7 @@
        ]
      }
    ],
-@@ -196,12 +248,40 @@
+@@ -199,12 +251,40 @@
          {
            "ip":"10.0.1.1",
            "afi":"ipv4",
          }
        ]
      }
-@@ -297,6 +377,24 @@
+@@ -300,6 +380,24 @@
            "ip":"10.0.1.3",
            "afi":"ipv4",
            "interfaceName":"eth-sw1",
            "active":true
          }
        ]
-@@ -317,6 +415,24 @@
+@@ -320,6 +418,24 @@
            "ip":"10.0.1.3",
            "afi":"ipv4",
            "interfaceName":"eth-sw1",
index 9809c316e87f06d2c7372990f147c00243d343f7..68b618e91db796b82fa8d3b00c24d5ed7c00f1b5 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step2/show_ipv6_route.ref      2020-09-25 17:46:58.514045373 -0300
-+++ rt2/step3/show_ipv6_route.ref      2020-09-25 17:48:06.570930838 -0300
+--- a/rt2/step2/show_ipv6_route.ref
++++ b/rt2/step3/show_ipv6_route.ref
 @@ -14,10 +14,34 @@
            "afi":"ipv6",
            "interfaceName":"eth-sw1",
index 180323e4c830a22639cc4488600150d354be210a..966e153a6b6ad5468b84c1d5dda5a0180f457084 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step2/show_mpls_table.ref      2020-09-25 17:46:56.086013807 -0300
-+++ rt2/step3/show_mpls_table.ref      2020-09-25 17:48:03.994897300 -0300
+--- a/rt2/step2/show_mpls_table.ref
++++ b/rt2/step3/show_mpls_table.ref
 @@ -7,7 +7,23 @@
          "type":"SR (IS-IS)",
          "outLabel":3,
index 12d45bbe07af85d774c1665017a10ed9af0ad6ac..dd75d76b9bcad648c0898df13f58b84db844afc9 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step3/show_ip_route.ref        2020-09-25 17:48:05.274913964 -0300
-+++ rt2/step4/show_ip_route.ref        2020-09-25 17:49:01.763649797 -0300
+--- a/rt2/step3/show_ip_route.ref
++++ b/rt2/step4/show_ip_route.ref
 @@ -15,36 +15,10 @@
            "afi":"ipv4",
            "interfaceName":"eth-sw1",
            ]
          }
        ],
-@@ -248,40 +177,12 @@
+@@ -251,40 +180,12 @@
          {
            "ip":"10.0.1.1",
            "afi":"ipv4",
index fdf658d59d2191f0d9dd2038ebf7173f8639370c..63731237ecb672b38a26912c42a1aaf3bf3d7fad 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step3/show_ipv6_route.ref      2020-09-25 17:48:06.570930838 -0300
-+++ rt2/step4/show_ipv6_route.ref      2020-09-25 17:49:02.995665853 -0300
+--- a/rt2/step3/show_ipv6_route.ref
++++ b/rt2/step4/show_ipv6_route.ref
 @@ -14,34 +14,10 @@
            "afi":"ipv6",
            "interfaceName":"eth-sw1",
            ]
          }
        ]
-@@ -162,19 +107,13 @@
+@@ -153,10 +98,7 @@
            "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-rt4-2",
+           "interfaceName":"eth-rt4-1",
 -          "active":true,
 -          "labels":[
 -            16051
          },
          {
            "fib":true,
+@@ -171,10 +113,7 @@
+           "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-rt4-1",
+           "interfaceName":"eth-rt4-2",
 -          "active":true,
 -          "labels":[
 -            16051
index a78f79c5765a5f2cba0f558e43e046603586bb49..3872ce4980dec569543cf8eec9f0afd2f9ace8b8 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step3/show_mpls_table.ref      2020-09-25 17:48:03.994897300 -0300
-+++ rt2/step4/show_mpls_table.ref      2020-09-25 17:49:00.551634001 -0300
+--- a/rt2/step3/show_mpls_table.ref
++++ b/rt2/step4/show_mpls_table.ref
 @@ -7,23 +7,7 @@
          "type":"SR (IS-IS)",
          "outLabel":3,
index 7d20fad3f453615837f407148f02fc5983e1c9dd..4d5636436ca8208dacdb23f3ea273a75e4f16069 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step4/show_ip_route.ref        2020-09-25 17:49:01.763649797 -0300
-+++ rt2/step5/show_ip_route.ref        2020-09-25 17:50:12.360570411 -0300
+--- a/rt2/step4/show_ip_route.ref
++++ b/rt2/step5/show_ip_route.ref
 @@ -15,10 +15,36 @@
            "afi":"ipv4",
            "interfaceName":"eth-sw1",
            ]
          }
        ],
-@@ -177,12 +248,40 @@
+@@ -180,12 +251,40 @@
          {
            "ip":"10.0.1.1",
            "afi":"ipv4",
index 93309643388cfd390be6b781ee73f52d3c07ca91..f9e0276f85ae5e02ba32d0fad3b7a0cfd8aa21e3 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step4/show_ipv6_route.ref      2020-09-25 17:49:02.995665853 -0300
-+++ rt2/step5/show_ipv6_route.ref      2020-09-25 17:50:13.636587060 -0300
+--- a/rt2/step4/show_ipv6_route.ref
++++ b/rt2/step5/show_ipv6_route.ref
 @@ -14,10 +14,34 @@
            "afi":"ipv6",
            "interfaceName":"eth-sw1",
            ]
          }
        ]
-@@ -107,13 +162,19 @@
+@@ -98,7 +153,10 @@
            "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-rt4-2",
+           "interfaceName":"eth-rt4-1",
 -          "active":true
 +          "active":true,
 +          "labels":[
          },
          {
            "fib":true,
+@@ -113,7 +171,10 @@
+           "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-rt4-1",
+           "interfaceName":"eth-rt4-2",
 -          "active":true
 +          "active":true,
 +          "labels":[
index b1e44a727f2b87e142ac5f303d62565846a15b32..6aebbd6c82b62d4947caae77b83086bac3b22a9d 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step4/show_mpls_table.ref      2020-09-25 17:49:00.551634001 -0300
-+++ rt2/step5/show_mpls_table.ref      2020-09-25 17:50:11.068553553 -0300
+--- a/rt2/step4/show_mpls_table.ref
++++ b/rt2/step5/show_mpls_table.ref
 @@ -7,7 +7,23 @@
          "type":"SR (IS-IS)",
          "outLabel":3,
index c92195d7040a9f97d4d952d4dae99b2990a21bc3..5e73b978448da4480db966c87a62c804e3d7fd15 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step6/show_ip_route.ref        2020-09-25 17:51:15.313392177 -0300
-+++ rt2/step7/show_ip_route.ref        2020-09-25 17:52:02.210004805 -0300
+--- a/rt2/step6/show_ip_route.ref
++++ b/rt2/step7/show_ip_route.ref
 @@ -15,36 +15,10 @@
            "afi":"ipv4",
            "interfaceName":"eth-sw1",
          }
        ]
      }
-@@ -248,40 +169,12 @@
+@@ -251,40 +172,12 @@
          {
            "ip":"10.0.1.1",
            "afi":"ipv4",
          }
        ]
      }
-@@ -296,30 +189,13 @@
+@@ -299,30 +192,13 @@
          {
            "ip":"10.0.2.4",
            "afi":"ipv4",
          }
        ]
      }
-@@ -335,29 +211,12 @@
+@@ -338,29 +214,12 @@
            "ip":"10.0.2.4",
            "afi":"ipv4",
            "interfaceName":"eth-rt4-1",
          }
        ]
      }
-@@ -494,31 +353,14 @@
+@@ -497,31 +356,14 @@
            "ip":"10.0.2.4",
            "afi":"ipv4",
            "interfaceName":"eth-rt4-1",
index 140c7b08bf1daee2143f87ed74756ec183976325..5dc4e59151aac30499ffa544fe36c7cb6f336d8c 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step6/show_ipv6_route.ref      2020-09-25 17:51:16.549408319 -0300
-+++ rt2/step7/show_ipv6_route.ref      2020-09-25 17:52:03.438020851 -0300
+--- a/rt2/step6/show_ipv6_route.ref
++++ b/rt2/step7/show_ipv6_route.ref
 @@ -14,34 +14,10 @@
            "afi":"ipv6",
            "interfaceName":"eth-sw1",
@@ -72,7 +72,7 @@
    ],
 @@ -106,9 +58,6 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt4-2",
+           "interfaceName":"eth-rt4-1",
            "active":true,
 -          "backupIndex":[
 -            0
@@ -82,7 +82,7 @@
            ]
 @@ -118,24 +67,10 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt4-1",
+           "interfaceName":"eth-rt4-2",
            "active":true,
 -          "backupIndex":[
 -            0
 @@ -153,28 +88,19 @@
            "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-sw1",
+           "interfaceName":"eth-rt4-1",
 -          "active":true,
 -          "labels":[
 -            16051
          {
            "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-rt4-2",
+           "interfaceName":"eth-sw1",
 -          "active":true,
 -          "labels":[
 -            16051
          {
            "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-rt4-1",
+           "interfaceName":"eth-rt4-2",
 -          "active":true,
 -          "labels":[
 -            16051
index f8476cd0bbf0182535b59903b89a5fe6ab9c2cea..6c0d7392f017f2cc184a1385548fe5db1115357f 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step6/show_mpls_table.ref      2020-09-25 17:51:14.073375985 -0300
-+++ rt2/step7/show_mpls_table.ref      2020-09-25 17:52:00.973988653 -0300
+--- a/rt2/step6/show_mpls_table.ref
++++ b/rt2/step7/show_mpls_table.ref
 @@ -7,23 +7,7 @@
          "type":"SR (IS-IS)",
          "outLabel":3,
index 7d5237e7405df62311305d0661a4ea85b9803b1a..f5df607613ed6bd5fc5de2d0799cdd2da65bfb42 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step7/show_ip_route.ref        2020-09-25 17:52:02.210004805 -0300
-+++ rt2/step8/show_ip_route.ref        2020-09-25 17:53:20.207024469 -0300
+--- a/rt2/step7/show_ip_route.ref
++++ b/rt2/step8/show_ip_route.ref
 @@ -15,10 +15,36 @@
            "afi":"ipv4",
            "interfaceName":"eth-sw1",
          }
        ]
      }
-@@ -169,12 +248,40 @@
+@@ -172,12 +251,40 @@
          {
            "ip":"10.0.1.1",
            "afi":"ipv4",
          }
        ]
      }
-@@ -189,13 +296,30 @@
+@@ -192,13 +299,30 @@
          {
            "ip":"10.0.2.4",
            "afi":"ipv4",
          }
        ]
      }
-@@ -211,12 +335,29 @@
+@@ -214,12 +338,29 @@
            "ip":"10.0.2.4",
            "afi":"ipv4",
            "interfaceName":"eth-rt4-1",
          }
        ]
      }
-@@ -353,14 +494,31 @@
+@@ -356,14 +497,31 @@
            "ip":"10.0.2.4",
            "afi":"ipv4",
            "interfaceName":"eth-rt4-1",
index 45322214e68b994ab6e82dc11b641f413ac2d670..125f36b1b449f22e3916a2613be78ee0a262ef3e 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step7/show_ipv6_route.ref      2020-09-25 17:52:03.438020851 -0300
-+++ rt2/step8/show_ipv6_route.ref      2020-09-25 17:53:21.443040633 -0300
+--- a/rt2/step7/show_ipv6_route.ref
++++ b/rt2/step8/show_ipv6_route.ref
 @@ -14,10 +14,34 @@
            "afi":"ipv6",
            "interfaceName":"eth-sw1",
@@ -72,7 +72,7 @@
    ],
 @@ -58,6 +106,9 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt4-2",
+           "interfaceName":"eth-rt4-1",
            "active":true,
 +          "backupIndex":[
 +            0
@@ -82,7 +82,7 @@
            ]
 @@ -67,10 +118,24 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt4-1",
+           "interfaceName":"eth-rt4-2",
            "active":true,
 +          "backupIndex":[
 +            0
 @@ -88,19 +153,28 @@
            "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-sw1",
+           "interfaceName":"eth-rt4-1",
 -          "active":true
 +          "active":true,
 +          "labels":[
          {
            "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-rt4-2",
+           "interfaceName":"eth-sw1",
 -          "active":true
 +          "active":true,
 +          "labels":[
          {
            "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-rt4-1",
+           "interfaceName":"eth-rt4-2",
 -          "active":true
 +          "active":true,
 +          "labels":[
index 083c6478028c2c38ed44122e01b59ccb9f0b154f..a1d5d795c5521cad2220b36f60d197d85e04de15 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step7/show_mpls_table.ref      2020-09-25 17:52:00.973988653 -0300
-+++ rt2/step8/show_mpls_table.ref      2020-09-25 17:53:18.923007676 -0300
+--- a/rt2/step7/show_mpls_table.ref
++++ b/rt2/step8/show_mpls_table.ref
 @@ -7,7 +7,23 @@
          "type":"SR (IS-IS)",
          "outLabel":3,
index 15370a0a6293a040ea3b6fc2045e5598494e204c..2475c639c19af9b2f2f13ff1da58d5cde5a87bee 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step8/show_ip_route.ref        2020-09-25 17:53:20.207024469 -0300
-+++ rt2/step9/show_ip_route.ref        2020-09-25 17:54:37.908041089 -0300
+--- a/rt2/step8/show_ip_route.ref
++++ b/rt2/step9/show_ip_route.ref
 @@ -31,7 +31,7 @@
            "interfaceName":"eth-rt4-1",
            "active":true,
@@ -72,7 +72,7 @@
            ]
          }
        ]
-@@ -271,7 +271,7 @@
+@@ -274,7 +274,7 @@
            "interfaceName":"eth-rt4-1",
            "active":true,
            "labels":[
@@ -81,7 +81,7 @@
            ]
          },
          {
-@@ -280,7 +280,7 @@
+@@ -283,7 +283,7 @@
            "interfaceName":"eth-rt4-2",
            "active":true,
            "labels":[
@@ -90,7 +90,7 @@
            ]
          }
        ]
-@@ -318,7 +318,7 @@
+@@ -321,7 +321,7 @@
            "interfaceName":"eth-sw1",
            "active":true,
            "labels":[
@@ -99,7 +99,7 @@
            ]
          }
        ]
-@@ -356,7 +356,7 @@
+@@ -359,7 +359,7 @@
            "interfaceName":"eth-sw1",
            "active":true,
            "labels":[
            ]
          }
        ]
-@@ -517,7 +517,7 @@
+@@ -520,7 +520,7 @@
            "interfaceName":"eth-sw1",
            "active":true,
            "labels":[
index 2585f32595dc25d4677e3cdc1c94b9e1c0744813..2d21fbcde2608e487aaba98a792ef2a5f79b3f02 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step8/show_ipv6_route.ref      2020-09-25 17:53:21.443040633 -0300
-+++ rt2/step9/show_ipv6_route.ref      2020-09-25 17:54:39.112056848 -0300
+--- a/rt2/step8/show_ipv6_route.ref
++++ b/rt2/step9/show_ipv6_route.ref
 @@ -29,7 +29,7 @@
            "interfaceName":"eth-rt4-1",
            "active":true,
@@ -46,7 +46,7 @@
            ]
          }
 @@ -155,7 +155,7 @@
-           "interfaceName":"eth-sw1",
+           "interfaceName":"eth-rt4-1",
            "active":true,
            "labels":[
 -            16051
@@ -55,7 +55,7 @@
          },
          {
 @@ -164,7 +164,7 @@
-           "interfaceName":"eth-rt4-2",
+           "interfaceName":"eth-sw1",
            "active":true,
            "labels":[
 -            16051
@@ -64,7 +64,7 @@
          },
          {
 @@ -173,7 +173,7 @@
-           "interfaceName":"eth-rt4-1",
+           "interfaceName":"eth-rt4-2",
            "active":true,
            "labels":[
 -            16051
index b90b889ebad2a452ba89a3c985fde5a409cefa7e..bc0ec3157ea26d4ed414ff57fd5cfe6f376d6162 100644 (file)
@@ -1,5 +1,5 @@
---- rt2/step8/show_mpls_table.ref      2020-09-25 17:53:18.923007676 -0300
-+++ rt2/step9/show_mpls_table.ref      2020-09-25 17:54:36.640024493 -0300
+--- a/rt2/step8/show_mpls_table.ref
++++ b/rt2/step9/show_mpls_table.ref
 @@ -17,12 +17,12 @@
      "backupNexthops":[
        {
index 8c37180daf2cdf2db2c38ef5bf32483d88266477..d70e9fe882e2f3eb08a8474787e06dd72b38ba28 100644 (file)
           "ip":"10.0.1.2",
           "afi":"ipv4",
           "interfaceName":"eth-sw1",
-          "active":true
+          "active":true,
+          "labels":[
+            16060
+          ]
         }
       ]
     }
index 5ddb24af5a0f93c309dd2fdc5fe9b3af6255c70c..058d33609b89740031bcee6a8f096013ea32367c 100644 (file)
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-sw1",
+          "interfaceName":"eth-rt5-1",
           "active":true,
           "labels":[
             16041
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt5-2",
+          "interfaceName":"eth-sw1",
           "active":true,
           "labels":[
             16041
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt5-1",
+          "interfaceName":"eth-rt5-2",
           "active":true,
           "labels":[
             16041
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt5-2",
+          "interfaceName":"eth-rt5-1",
           "active":true,
           "backupIndex":[
             0
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt5-1",
+          "interfaceName":"eth-rt5-2",
           "active":true,
           "backupIndex":[
             0
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt5-2",
+          "interfaceName":"eth-rt5-1",
           "active":true,
           "backupIndex":[
             0
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt5-1",
+          "interfaceName":"eth-rt5-2",
           "active":true,
           "backupIndex":[
             0
         {
           "afi":"ipv6",
           "interfaceName":"eth-sw1",
-          "active":true
+          "active":true,
+          "labels":[
+            16061
+          ]
         }
       ]
     }
index f68d1f4244f248d72e7127683d9df59717cbc2d0..1912df3f050cfee0c634bf106455b6990562adaf 100644 (file)
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16060,
         "nexthop":"10.0.1.2"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16061,
         "interface":"eth-sw1"
       }
     ]
index 707f95495d85a1150496c0d0b0e28b6117206b1e..9ba73b057a0e1e4b720a208d55d08d9740818ddf 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step3/show_ip_route.ref        2020-09-25 17:48:05.506916984 -0300
-+++ rt3/step4/show_ip_route.ref        2020-09-25 17:49:01.963652403 -0300
+--- a/rt3/step3/show_ip_route.ref
++++ b/rt3/step4/show_ip_route.ref
 @@ -15,36 +15,10 @@
            "afi":"ipv4",
            "interfaceName":"eth-sw1",
        ]
      }
    ],
-@@ -248,40 +169,12 @@
+@@ -251,40 +172,12 @@
          {
            "ip":"10.0.1.1",
            "afi":"ipv4",
          }
        ]
      }
-@@ -372,30 +265,13 @@
+@@ -375,30 +268,13 @@
          {
            "ip":"10.0.4.5",
            "afi":"ipv4",
          }
        ]
      }
-@@ -411,29 +287,12 @@
+@@ -414,29 +290,12 @@
            "ip":"10.0.4.5",
            "afi":"ipv4",
            "interfaceName":"eth-rt5-1",
          }
        ]
      }
-@@ -528,31 +387,14 @@
+@@ -531,31 +390,14 @@
            "ip":"10.0.4.5",
            "afi":"ipv4",
            "interfaceName":"eth-rt5-1",
index 76d0ebc913a6159e71fc90b77598f1aedbddaf5c..04f61c4eb40b4fc4ec174a66536d68bfb54dbafc 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step3/show_ipv6_route.ref      2020-09-25 17:48:06.790933702 -0300
-+++ rt3/step4/show_ipv6_route.ref      2020-09-25 17:49:03.199668512 -0300
+--- a/rt3/step3/show_ipv6_route.ref
++++ b/rt3/step4/show_ipv6_route.ref
 @@ -14,34 +14,10 @@
            "afi":"ipv6",
            "interfaceName":"eth-sw1",
@@ -73,7 +73,7 @@
 @@ -105,28 +57,19 @@
            "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-sw1",
+           "interfaceName":"eth-rt5-1",
 -          "active":true,
 -          "labels":[
 -            16041
@@ -83,7 +83,7 @@
          {
            "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-rt5-2",
+           "interfaceName":"eth-sw1",
 -          "active":true,
 -          "labels":[
 -            16041
@@ -93,7 +93,7 @@
          {
            "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-rt5-1",
+           "interfaceName":"eth-rt5-2",
 -          "active":true,
 -          "labels":[
 -            16041
      }
 @@ -146,9 +89,6 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt5-2",
+           "interfaceName":"eth-rt5-1",
            "active":true,
 -          "backupIndex":[
 -            0
            ]
 @@ -158,24 +98,10 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt5-1",
+           "interfaceName":"eth-rt5-2",
            "active":true,
 -          "backupIndex":[
 -            0
index b888c9d273215f0cc180ceb774b400bae60ea05e..b3588ca791326f985980ab537d9e966a5bd87432 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step3/show_mpls_table.ref      2020-09-25 17:48:04.214900164 -0300
-+++ rt3/step4/show_mpls_table.ref      2020-09-25 17:49:00.759636711 -0300
+--- a/rt3/step3/show_mpls_table.ref
++++ b/rt3/step4/show_mpls_table.ref
 @@ -7,23 +7,7 @@
          "type":"SR (IS-IS)",
          "outLabel":3,
index 8eac75bec7e4a6117d825e85b48da8d5bc4aabcc..1af024fc2e78088cf740185d4ee4d7893f4714be 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step4/show_ip_route.ref        2020-09-25 17:49:01.963652403 -0300
-+++ rt3/step5/show_ip_route.ref        2020-09-25 17:50:12.592573438 -0300
+--- a/rt3/step4/show_ip_route.ref
++++ b/rt3/step5/show_ip_route.ref
 @@ -15,10 +15,36 @@
            "afi":"ipv4",
            "interfaceName":"eth-sw1",
        ]
      }
    ],
-@@ -169,12 +248,40 @@
+@@ -172,12 +251,40 @@
          {
            "ip":"10.0.1.1",
            "afi":"ipv4",
          }
        ]
      }
-@@ -265,13 +372,30 @@
+@@ -268,13 +375,30 @@
          {
            "ip":"10.0.4.5",
            "afi":"ipv4",
          }
        ]
      }
-@@ -287,12 +411,29 @@
+@@ -290,12 +414,29 @@
            "ip":"10.0.4.5",
            "afi":"ipv4",
            "interfaceName":"eth-rt5-1",
          }
        ]
      }
-@@ -387,14 +528,31 @@
+@@ -390,14 +531,31 @@
            "ip":"10.0.4.5",
            "afi":"ipv4",
            "interfaceName":"eth-rt5-1",
index fc55267ad1618da848dc3f37b5e4080a51fd75df..7cc79d0e58585d18256c62fbff4b8021f96dffc2 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step4/show_ipv6_route.ref      2020-09-25 17:49:03.199668512 -0300
-+++ rt3/step5/show_ipv6_route.ref      2020-09-25 17:50:13.840589722 -0300
+--- a/rt3/step4/show_ipv6_route.ref
++++ b/rt3/step5/show_ipv6_route.ref
 @@ -14,10 +14,34 @@
            "afi":"ipv6",
            "interfaceName":"eth-sw1",
@@ -73,7 +73,7 @@
 @@ -57,19 +105,28 @@
            "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-sw1",
+           "interfaceName":"eth-rt5-1",
 -          "active":true
 +          "active":true,
 +          "labels":[
@@ -83,7 +83,7 @@
          {
            "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-rt5-2",
+           "interfaceName":"eth-sw1",
 -          "active":true
 +          "active":true,
 +          "labels":[
@@ -93,7 +93,7 @@
          {
            "fib":true,
            "afi":"ipv6",
-           "interfaceName":"eth-rt5-1",
+           "interfaceName":"eth-rt5-2",
 -          "active":true
 +          "active":true,
 +          "labels":[
      }
 @@ -89,6 +146,9 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt5-2",
+           "interfaceName":"eth-rt5-1",
            "active":true,
 +          "backupIndex":[
 +            0
            ]
 @@ -98,10 +158,24 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt5-1",
+           "interfaceName":"eth-rt5-2",
            "active":true,
 +          "backupIndex":[
 +            0
index 4ed491e2416ca87494552ef0c4fd83d0f8e9ce79..75a0f01f551428f5302cc750d8ea80d229647d9c 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step4/show_mpls_table.ref      2020-09-25 17:49:00.759636711 -0300
-+++ rt3/step5/show_mpls_table.ref      2020-09-25 17:50:11.280556320 -0300
+--- a/rt3/step4/show_mpls_table.ref
++++ b/rt3/step5/show_mpls_table.ref
 @@ -7,7 +7,23 @@
          "type":"SR (IS-IS)",
          "outLabel":3,
index 9273c75352640fa21c093191fa62661c9dea2544..c814a2876b4dc744f0ae64ac5190749b9da8a361 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step5/show_ip_route.ref        2020-09-25 17:50:12.592573438 -0300
-+++ rt3/step6/show_ip_route.ref        2020-09-25 17:51:15.521394894 -0300
+--- a/rt3/step5/show_ip_route.ref
++++ b/rt3/step6/show_ip_route.ref
 @@ -31,7 +31,7 @@
            "interfaceName":"eth-rt5-1",
            "active":true,
@@ -81,7 +81,7 @@
            ]
          }
        ],
-@@ -271,7 +271,7 @@
+@@ -274,7 +274,7 @@
            "interfaceName":"eth-rt5-1",
            "active":true,
            "labels":[
@@ -90,7 +90,7 @@
            ]
          },
          {
-@@ -280,7 +280,7 @@
+@@ -283,7 +283,7 @@
            "interfaceName":"eth-rt5-2",
            "active":true,
            "labels":[
index f50be893e476a1261948e7a9298daf393b135af2..6f9405f20ce9b75fac4e726fd28ff18595c739e4 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step5/show_ipv6_route.ref      2020-09-25 17:50:13.840589722 -0300
-+++ rt3/step6/show_ipv6_route.ref      2020-09-25 17:51:16.757411035 -0300
+--- a/rt3/step5/show_ipv6_route.ref
++++ b/rt3/step6/show_ipv6_route.ref
 @@ -29,7 +29,7 @@
            "interfaceName":"eth-rt5-1",
            "active":true,
@@ -36,8 +36,8 @@
              16021
            ]
          }
-@@ -116,7 +116,7 @@
-           "interfaceName":"eth-rt5-2",
+@@ -107,7 +107,7 @@
+           "interfaceName":"eth-rt5-1",
            "active":true,
            "labels":[
 -            16041
@@ -46,7 +46,7 @@
          },
          {
 @@ -125,7 +125,7 @@
-           "interfaceName":"eth-rt5-1",
+           "interfaceName":"eth-rt5-2",
            "active":true,
            "labels":[
 -            16041
index b63a728ef101da3637c0f7be25247909242a835d..d8c39685de7c7aca7ac4ee4130a8732521aab879 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step5/show_mpls_table.ref      2020-09-25 17:50:11.280556320 -0300
-+++ rt3/step6/show_mpls_table.ref      2020-09-25 17:51:14.281378700 -0300
+--- a/rt3/step5/show_mpls_table.ref
++++ b/rt3/step6/show_mpls_table.ref
 @@ -17,12 +17,12 @@
      "backupNexthops":[
        {
index 0ae87afa3bad5b1bf1914ae051ab6e29d8eae2f8..c928fcdb4bf18d542e5e7c65e762db1b70d7d0e9 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step6/show_ip_route.ref        2020-09-25 17:51:15.521394894 -0300
-+++ rt3/step7/show_ip_route.ref        2020-09-25 17:52:02.414007470 -0300
+--- a/rt3/step6/show_ip_route.ref
++++ b/rt3/step7/show_ip_route.ref
 @@ -158,9 +158,6 @@
            "active":true,
            "backupIndex":[
index f392f644c04977f5cde9215e44a2ec2cf374aa55..0170971781cffd906de60e8a2aae595d357cb9eb 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step6/show_ipv6_route.ref      2020-09-25 17:51:16.757411035 -0300
-+++ rt3/step7/show_ipv6_route.ref      2020-09-25 17:52:03.650023622 -0300
+--- a/rt3/step6/show_ipv6_route.ref
++++ b/rt3/step7/show_ipv6_route.ref
 @@ -148,9 +148,6 @@
            "active":true,
            "backupIndex":[
index b74eb9579cd3b1d97e587b55161d93fb3fe98bc9..d7a3ed978f369874ee258d12378d06e710c96aa8 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step6/show_mpls_table.ref      2020-09-25 17:51:14.281378700 -0300
-+++ rt3/step7/show_mpls_table.ref      2020-09-25 17:52:01.181991371 -0300
+--- a/rt3/step6/show_mpls_table.ref
++++ b/rt3/step7/show_mpls_table.ref
 @@ -159,68 +159,6 @@
        }
      ]
index 25b42f282506404624ae2a53459dc6bf3d7e9b57..41a7ff32552e083fd53362cdcab1db70eb3834db 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step7/show_ip_route.ref        2020-09-25 17:52:02.414007470 -0300
-+++ rt3/step8/show_ip_route.ref        2020-09-25 17:53:20.419027241 -0300
+--- a/rt3/step7/show_ip_route.ref
++++ b/rt3/step8/show_ip_route.ref
 @@ -158,6 +158,9 @@
            "active":true,
            "backupIndex":[
index 42d9356c8ad791bfc2786e259cef758a5b3aaebf..bd49f8606ba8cb6bf7e250e2672b4a706ab20be7 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step7/show_ipv6_route.ref      2020-09-25 17:52:03.650023622 -0300
-+++ rt3/step8/show_ipv6_route.ref      2020-09-25 17:53:21.643043250 -0300
+--- a/rt3/step7/show_ipv6_route.ref
++++ b/rt3/step8/show_ipv6_route.ref
 @@ -148,6 +148,9 @@
            "active":true,
            "backupIndex":[
index bd40f954eb781b790aa2ac0c83706ede04e7e744..4cc69b66f24d46735cf72d0f56cf54bdfb48a5fb 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step7/show_mpls_table.ref      2020-09-25 17:52:01.181991371 -0300
-+++ rt3/step8/show_mpls_table.ref      2020-09-25 17:53:19.135010448 -0300
+--- a/rt3/step7/show_mpls_table.ref
++++ b/rt3/step8/show_mpls_table.ref
 @@ -159,6 +159,68 @@
        }
      ]
index 687e84ad40a2ac449221d0682b3f7113c0335a8c..cc0a482eee4e2c71c3a88aa8a08a6ead483e8268 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step8/show_ip_route.ref        2020-09-25 17:53:20.419027241 -0300
-+++ rt3/step9/show_ip_route.ref        2020-09-25 17:54:38.112043759 -0300
+--- a/rt3/step8/show_ip_route.ref
++++ b/rt3/step9/show_ip_route.ref
 @@ -185,7 +185,7 @@
            "active":true,
            "labels":[
index 4b76be66ac8458df84a086f4ee966f5f30f36308..650b982f0b620fe7806c03c97edb87e53cbce325 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step8/show_ipv6_route.ref      2020-09-25 17:53:21.643043250 -0300
-+++ rt3/step9/show_ipv6_route.ref      2020-09-25 17:54:39.320059571 -0300
+--- a/rt3/step8/show_ipv6_route.ref
++++ b/rt3/step9/show_ipv6_route.ref
 @@ -173,7 +173,7 @@
            "active":true,
            "labels":[
index 6f6451e510358332c612403f4722698101ab7ecc..8ce4f1d266100e050812761d560963247ab1d840 100644 (file)
@@ -1,5 +1,5 @@
---- rt3/step8/show_mpls_table.ref      2020-09-25 17:53:19.135010448 -0300
-+++ rt3/step9/show_mpls_table.ref      2020-09-25 17:54:36.852027268 -0300
+--- a/rt3/step8/show_mpls_table.ref
++++ b/rt3/step9/show_mpls_table.ref
 @@ -159,13 +159,13 @@
        }
      ]
@@ -31,7 +31,7 @@
        {
          "type":"SR (IS-IS)",
 -        "outLabel":16040,
-+        "outLabel":3,
++        "outLabel":16060,
          "nexthop":"10.0.1.2"
        }
      ]
@@ -63,7 +63,7 @@
        {
          "type":"SR (IS-IS)",
 -        "outLabel":16041,
-+        "outLabel":3,
++        "outLabel":16061,
          "interface":"eth-sw1"
        }
      ]
@@ -94,7 +94,7 @@
      "backupNexthops":[
        {
          "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16060,
 +        "outLabel":16040,
          "nexthop":"10.0.1.2"
        }
      "backupNexthops":[
        {
          "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16061,
 +        "outLabel":16041,
          "interface":"eth-sw1"
        }
index 168b90a3f6bd12ccc0b40c21a53c7ddfd4c615e2..0ef5d1bc3f82d65a2413060ab49c6e2b63f9ed13 100644 (file)
           "ip":"10.0.6.5",
           "afi":"ipv4",
           "interfaceName":"eth-rt5",
-          "active":true
+          "active":true,
+          "labels":[
+            16010
+          ]
         }
       ]
     }
           "ip":"10.0.7.6",
           "afi":"ipv4",
           "interfaceName":"eth-rt6",
-          "active":true
+          "active":true,
+          "labels":[
+            16050
+          ]
         }
       ]
     }
           "ip":"10.0.6.5",
           "afi":"ipv4",
           "interfaceName":"eth-rt5",
-          "active":true
+          "active":true,
+          "labels":[
+            16060
+          ]
         }
       ]
     }
index a4442ee0895a4b284004e18554a976bdc45302b7..b640df30c1fb4fd133405e5def92c5d12bdff841 100644 (file)
@@ -12,7 +12,7 @@
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt2-1",
+          "interfaceName":"eth-rt2-2",
           "active":true,
           "backupIndex":[
             0
@@ -24,7 +24,7 @@
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt2-2",
+          "interfaceName":"eth-rt2-1",
           "active":true,
           "backupIndex":[
             0
         {
           "afi":"ipv6",
           "interfaceName":"eth-rt5",
-          "active":true
+          "active":true,
+          "labels":[
+            16011
+          ]
         }
       ]
     }
@@ -56,7 +59,7 @@
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt2-1",
+          "interfaceName":"eth-rt2-2",
           "active":true,
           "backupIndex":[
             0
@@ -68,7 +71,7 @@
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt2-2",
+          "interfaceName":"eth-rt2-1",
           "active":true,
           "backupIndex":[
             0
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt2-1",
+          "interfaceName":"eth-rt2-2",
           "active":true,
           "labels":[
             16031
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt5",
+          "interfaceName":"eth-rt2-1",
           "active":true,
           "labels":[
             16031
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt2-2",
+          "interfaceName":"eth-rt5",
           "active":true,
           "labels":[
             16031
         {
           "afi":"ipv6",
           "interfaceName":"eth-rt6",
-          "active":true
+          "active":true,
+          "labels":[
+            16051
+          ]
         }
       ]
     }
         {
           "afi":"ipv6",
           "interfaceName":"eth-rt5",
-          "active":true
+          "active":true,
+          "labels":[
+            16061
+          ]
         }
       ]
     }
index 18354e947d2c9e75edc931d255fb7b62f5e0f953..f60937ccbcd717331cf083a40c867f62a74ccf43 100644 (file)
@@ -25,7 +25,7 @@
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16010,
         "nexthop":"10.0.6.5"
       }
     ]
@@ -56,7 +56,7 @@
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16011,
         "interface":"eth-rt5"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16050,
         "nexthop":"10.0.7.6"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16051,
         "interface":"eth-rt6"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16060,
         "nexthop":"10.0.6.5"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16061,
         "interface":"eth-rt5"
       }
     ]
index 7dcdb744ac905fd7a601619fea05d21d601260fe..8b115c2058044b948d2afd868a9a6dacdeb62083 100644 (file)
@@ -1,5 +1,5 @@
---- rt4/step3/show_ip_route.ref        2020-09-25 17:48:05.722919797 -0300
-+++ rt4/step4/show_ip_route.ref        2020-09-25 17:49:02.163655010 -0300
+--- a/rt4/step3/show_ip_route.ref
++++ b/rt4/step4/show_ip_route.ref
 @@ -15,9 +15,6 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt2-1",
            "labels":[
              16010
            ]
-@@ -28,21 +25,10 @@
+@@ -28,20 +25,6 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt2-2",
            "active":true,
 -          "backupIndex":[
 -            0
 -          ],
-           "labels":[
-             16010
-           ]
-         }
+-          "labels":[
+-            16010
+-          ]
+-        }
 -      ],
 -      "backupNexthops":[
 -        {
 -          "ip":"10.0.6.5",
 -          "afi":"ipv4",
 -          "interfaceName":"eth-rt5",
--          "active":true
--        }
-       ]
-     }
-   ],
-@@ -62,9 +48,6 @@
+-          "active":true,
+           "labels":[
+             16010
+           ]
+@@ -65,9 +48,6 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt2-1",
            "active":true,
@@ -42,7 +41,7 @@
            "labels":[
              3
            ]
-@@ -75,25 +58,10 @@
+@@ -78,25 +58,10 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt2-2",
            "active":true,
@@ -68,7 +67,7 @@
        ]
      }
    ],
-@@ -156,21 +124,10 @@
+@@ -159,24 +124,10 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt5",
            "active":true,
 -          "ip":"10.0.7.6",
 -          "afi":"ipv4",
 -          "interfaceName":"eth-rt6",
--          "active":true
+-          "active":true,
+-          "labels":[
+-            16050
+-          ]
 -        }
        ]
      }
    ],
-@@ -190,21 +147,10 @@
+@@ -196,24 +147,10 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt6",
            "active":true,
 -          "ip":"10.0.6.5",
 -          "afi":"ipv4",
 -          "interfaceName":"eth-rt5",
--          "active":true
+-          "active":true,
+-          "labels":[
+-            16060
+-          ]
 -        }
        ]
      }
    ],
-@@ -223,27 +169,13 @@
+@@ -232,27 +169,13 @@
            "ip":"10.0.2.2",
            "afi":"ipv4",
            "interfaceName":"eth-rt2-1",
            "active":true
          }
        ]
-@@ -259,30 +191,13 @@
+@@ -268,30 +191,13 @@
          {
            "ip":"10.0.2.2",
            "afi":"ipv4",
          }
        ]
      }
-@@ -298,29 +213,12 @@
+@@ -307,29 +213,12 @@
            "ip":"10.0.2.2",
            "afi":"ipv4",
            "interfaceName":"eth-rt2-1",
          }
        ]
      }
-@@ -340,31 +238,6 @@
+@@ -349,31 +238,6 @@
            "ip":"10.0.6.5",
            "afi":"ipv4",
            "interfaceName":"eth-rt5",
            "active":true
          }
        ]
-@@ -385,31 +258,6 @@
+@@ -394,31 +258,6 @@
            "ip":"10.0.6.5",
            "afi":"ipv4",
            "interfaceName":"eth-rt5",
            "active":true
          }
        ]
-@@ -425,18 +273,7 @@
+@@ -434,18 +273,7 @@
          {
            "ip":"10.0.6.5",
            "afi":"ipv4",
          }
        ]
      }
-@@ -451,18 +288,7 @@
+@@ -460,18 +288,7 @@
          {
            "ip":"10.0.7.6",
            "afi":"ipv4",
index b84ceaff1a7aae3630fd2bed6fdefaf6241c769a..7f39285089687a0c7c919e726bf48fae8c735e1b 100644 (file)
@@ -1,8 +1,8 @@
---- rt4/step3/show_ipv6_route.ref      2020-09-25 17:48:06.998936410 -0300
-+++ rt4/step4/show_ipv6_route.ref      2020-09-25 17:49:03.399671119 -0300
+--- a/rt4/step3/show_ipv6_route.ref
++++ b/rt4/step4/show_ipv6_route.ref
 @@ -14,9 +14,6 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt2-1",
+           "interfaceName":"eth-rt2-2",
            "active":true,
 -          "backupIndex":[
 -            0
            "labels":[
              16011
            ]
-@@ -26,20 +23,10 @@
+@@ -26,19 +23,6 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt2-2",
+           "interfaceName":"eth-rt2-1",
            "active":true,
 -          "backupIndex":[
 -            0
 -          ],
-           "labels":[
-             16011
-           ]
-         }
+-          "labels":[
+-            16011
+-          ]
+-        }
 -      ],
 -      "backupNexthops":[
 -        {
 -          "afi":"ipv6",
 -          "interfaceName":"eth-rt5",
--          "active":true
--        }
-       ]
-     }
-   ],
-@@ -58,9 +45,6 @@
+-          "active":true,
+           "labels":[
+             16011
+           ]
+@@ -61,9 +45,6 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt2-1",
+           "interfaceName":"eth-rt2-2",
            "active":true,
 -          "backupIndex":[
 -            0
@@ -41,9 +40,9 @@
            "labels":[
              3
            ]
-@@ -70,24 +54,10 @@
+@@ -73,24 +54,10 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt2-2",
+           "interfaceName":"eth-rt2-1",
            "active":true,
 -          "backupIndex":[
 -            0
@@ -66,7 +65,7 @@
        ]
      }
    ],
-@@ -146,20 +116,10 @@
+@@ -149,23 +116,10 @@
            "afi":"ipv6",
            "interfaceName":"eth-rt5",
            "active":true,
 -        {
 -          "afi":"ipv6",
 -          "interfaceName":"eth-rt6",
--          "active":true
+-          "active":true,
+-          "labels":[
+-            16051
+-          ]
 -        }
        ]
      }
    ],
-@@ -178,20 +138,10 @@
+@@ -184,23 +138,10 @@
            "afi":"ipv6",
            "interfaceName":"eth-rt6",
            "active":true,
 -        {
 -          "afi":"ipv6",
 -          "interfaceName":"eth-rt5",
--          "active":true
+-          "active":true,
+-          "labels":[
+-            16061
+-          ]
 -        }
        ]
      }
index 70e0108b0dcf1e1ac329bf03fd34674d78280504..3dcd36c1768f7fc73c4f25e2a87348c30348a9a7 100644 (file)
@@ -1,5 +1,5 @@
---- rt4/step3/show_mpls_table.ref      2020-09-25 17:48:04.418902820 -0300
-+++ rt4/step4/show_mpls_table.ref      2020-09-25 17:49:00.959639319 -0300
+--- a/rt4/step3/show_mpls_table.ref
++++ b/rt4/step4/show_mpls_table.ref
 @@ -7,26 +7,13 @@
          "type":"SR (IS-IS)",
          "outLabel":16010,
@@ -23,7 +23,7 @@
 -    "backupNexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16010,
 -        "nexthop":"10.0.6.5"
 +        "nexthop":"10.0.2.2"
        }
@@ -52,7 +52,7 @@
 -    "backupNexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16011,
 -        "interface":"eth-rt5"
 +        "interface":"eth-rt2-1"
        }
 -    "backupNexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16050,
 -        "nexthop":"10.0.7.6"
 +        "nexthop":"10.0.6.5"
        }
 -    "backupNexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16051,
 -        "interface":"eth-rt6"
 +        "interface":"eth-rt5"
        }
 -    "backupNexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16060,
 -        "nexthop":"10.0.6.5"
 +        "nexthop":"10.0.7.6"
        }
 -    "backupNexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16061,
 -        "interface":"eth-rt5"
 +        "interface":"eth-rt6"
        }
index aa319a3232fa8218d7a59aa7ab26f7ef65d81b95..484a3147dcd18670aa53f655a60a8aa8c714105f 100644 (file)
@@ -1,5 +1,5 @@
---- rt4/step4/show_ip_route.ref        2020-09-25 17:49:02.163655010 -0300
-+++ rt4/step5/show_ip_route.ref        2020-09-25 17:50:12.800576153 -0300
+--- a/rt4/step4/show_ip_route.ref
++++ b/rt4/step5/show_ip_route.ref
 @@ -15,6 +15,9 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt2-1",
            "labels":[
              16010
            ]
-@@ -25,10 +28,21 @@
+@@ -25,6 +28,20 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt2-2",
            "active":true,
 +          "backupIndex":[
 +            0
 +          ],
-           "labels":[
-             16010
-           ]
-         }
++          "labels":[
++            16010
++          ]
++        }
 +      ],
 +      "backupNexthops":[
 +        {
 +          "ip":"10.0.6.5",
 +          "afi":"ipv4",
 +          "interfaceName":"eth-rt5",
-+          "active":true
-+        }
-       ]
-     }
-   ],
-@@ -48,6 +62,9 @@
++          "active":true,
+           "labels":[
+             16010
+           ]
+@@ -48,6 +65,9 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt2-1",
            "active":true,
@@ -42,7 +41,7 @@
            "labels":[
              3
            ]
-@@ -58,10 +75,25 @@
+@@ -58,10 +78,25 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt2-2",
            "active":true,
@@ -68,7 +67,7 @@
        ]
      }
    ],
-@@ -124,10 +156,21 @@
+@@ -124,10 +159,24 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt5",
            "active":true,
 +          "ip":"10.0.7.6",
 +          "afi":"ipv4",
 +          "interfaceName":"eth-rt6",
-+          "active":true
++          "active":true,
++          "labels":[
++            16050
++          ]
 +        }
        ]
      }
    ],
-@@ -147,10 +190,21 @@
+@@ -147,10 +196,24 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt6",
            "active":true,
 +          "ip":"10.0.6.5",
 +          "afi":"ipv4",
 +          "interfaceName":"eth-rt5",
-+          "active":true
++          "active":true,
++          "labels":[
++            16060
++          ]
 +        }
        ]
      }
    ],
-@@ -169,13 +223,27 @@
+@@ -169,13 +232,27 @@
            "ip":"10.0.2.2",
            "afi":"ipv4",
            "interfaceName":"eth-rt2-1",
            "active":true
          }
        ]
-@@ -191,13 +259,30 @@
+@@ -191,13 +268,30 @@
          {
            "ip":"10.0.2.2",
            "afi":"ipv4",
          }
        ]
      }
-@@ -213,12 +298,29 @@
+@@ -213,12 +307,29 @@
            "ip":"10.0.2.2",
            "afi":"ipv4",
            "interfaceName":"eth-rt2-1",
          }
        ]
      }
-@@ -238,6 +340,31 @@
+@@ -238,6 +349,31 @@
            "ip":"10.0.6.5",
            "afi":"ipv4",
            "interfaceName":"eth-rt5",
            "active":true
          }
        ]
-@@ -258,6 +385,31 @@
+@@ -258,6 +394,31 @@
            "ip":"10.0.6.5",
            "afi":"ipv4",
            "interfaceName":"eth-rt5",
            "active":true
          }
        ]
-@@ -273,7 +425,18 @@
+@@ -273,7 +434,18 @@
          {
            "ip":"10.0.6.5",
            "afi":"ipv4",
          }
        ]
      }
-@@ -288,7 +451,18 @@
+@@ -288,7 +460,18 @@
          {
            "ip":"10.0.7.6",
            "afi":"ipv4",
index 1bd207854c7433e1826c7fb0e5f0e761939ea822..3ad008512041e7b73aef25991c34fae17ba40cba 100644 (file)
@@ -1,8 +1,8 @@
---- rt4/step4/show_ipv6_route.ref      2020-09-25 17:49:03.399671119 -0300
-+++ rt4/step5/show_ipv6_route.ref      2020-09-25 17:50:14.040592332 -0300
+--- a/rt4/step4/show_ipv6_route.ref
++++ b/rt4/step5/show_ipv6_route.ref
 @@ -14,6 +14,9 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt2-1",
+           "interfaceName":"eth-rt2-2",
            "active":true,
 +          "backupIndex":[
 +            0
            "labels":[
              16011
            ]
-@@ -23,10 +26,20 @@
+@@ -23,6 +26,19 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt2-2",
+           "interfaceName":"eth-rt2-1",
            "active":true,
 +          "backupIndex":[
 +            0
 +          ],
-           "labels":[
-             16011
-           ]
-         }
++          "labels":[
++            16011
++          ]
++        }
 +      ],
 +      "backupNexthops":[
 +        {
 +          "afi":"ipv6",
 +          "interfaceName":"eth-rt5",
-+          "active":true
-+        }
-       ]
-     }
-   ],
-@@ -45,6 +58,9 @@
++          "active":true,
+           "labels":[
+             16011
+           ]
+@@ -45,6 +61,9 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt2-1",
+           "interfaceName":"eth-rt2-2",
            "active":true,
 +          "backupIndex":[
 +            0
@@ -41,9 +40,9 @@
            "labels":[
              3
            ]
-@@ -54,10 +70,24 @@
+@@ -54,10 +73,24 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt2-2",
+           "interfaceName":"eth-rt2-1",
            "active":true,
 +          "backupIndex":[
 +            0
@@ -66,7 +65,7 @@
        ]
      }
    ],
-@@ -116,10 +146,20 @@
+@@ -116,10 +149,23 @@
            "afi":"ipv6",
            "interfaceName":"eth-rt5",
            "active":true,
 +        {
 +          "afi":"ipv6",
 +          "interfaceName":"eth-rt6",
-+          "active":true
++          "active":true,
++          "labels":[
++            16051
++          ]
 +        }
        ]
      }
    ],
-@@ -138,10 +178,20 @@
+@@ -138,10 +184,23 @@
            "afi":"ipv6",
            "interfaceName":"eth-rt6",
            "active":true,
 +        {
 +          "afi":"ipv6",
 +          "interfaceName":"eth-rt5",
-+          "active":true
++          "active":true,
++          "labels":[
++            16061
++          ]
 +        }
        ]
      }
index 664b129a1b9c1fe46d7536ef94405d140ae3d0f1..20e363375bc87f4680cd469bbd6530b89730c767 100644 (file)
@@ -1,5 +1,5 @@
---- rt4/step4/show_mpls_table.ref      2020-09-25 17:49:00.959639319 -0300
-+++ rt4/step5/show_mpls_table.ref      2020-09-25 17:50:11.488559034 -0300
+--- a/rt4/step4/show_mpls_table.ref
++++ b/rt4/step5/show_mpls_table.ref
 @@ -7,13 +7,26 @@
          "type":"SR (IS-IS)",
          "outLabel":16010,
@@ -24,7 +24,7 @@
 +    "backupNexthops":[
 +      {
 +        "type":"SR (IS-IS)",
-+        "outLabel":3,
++        "outLabel":16010,
 +        "nexthop":"10.0.6.5"
        }
      ]
@@ -53,7 +53,7 @@
 +    "backupNexthops":[
 +      {
 +        "type":"SR (IS-IS)",
-+        "outLabel":3,
++        "outLabel":16011,
 +        "interface":"eth-rt5"
        }
      ]
 +    "backupNexthops":[
 +      {
 +        "type":"SR (IS-IS)",
-+        "outLabel":3,
++        "outLabel":16050,
 +        "nexthop":"10.0.7.6"
        }
      ]
 +    "backupNexthops":[
 +      {
 +        "type":"SR (IS-IS)",
-+        "outLabel":3,
++        "outLabel":16051,
 +        "interface":"eth-rt6"
        }
      ]
 +    "backupNexthops":[
 +      {
 +        "type":"SR (IS-IS)",
-+        "outLabel":3,
++        "outLabel":16060,
 +        "nexthop":"10.0.6.5"
        }
      ]
 +    "backupNexthops":[
 +      {
 +        "type":"SR (IS-IS)",
-+        "outLabel":3,
++        "outLabel":16061,
 +        "interface":"eth-rt5"
        }
      ]
index c758b89839c4f06e5ca26fff4b1e090467daf3df..9070414730e036a2f4e0f28454c6758f75cf35ed 100644 (file)
@@ -1,6 +1,15 @@
---- rt4/step5/show_ip_route.ref        2020-09-25 17:50:12.800576153 -0300
-+++ rt4/step6/show_ip_route.ref        2020-09-25 17:51:15.725397558 -0300
-@@ -90,7 +90,7 @@
+--- a/rt4/step5/show_ip_route.ref
++++ b/rt4/step6/show_ip_route.ref
+@@ -43,7 +43,7 @@
+           "interfaceName":"eth-rt5",
+           "active":true,
+           "labels":[
+-            16010
++            30010
+           ]
+         }
+       ]
+@@ -93,7 +93,7 @@
            "interfaceName":"eth-rt5",
            "active":true,
            "labels":[
@@ -9,7 +18,7 @@
              16020
            ]
          }
-@@ -134,7 +134,7 @@
+@@ -137,7 +137,7 @@
            "interfaceName":"eth-rt5",
            "active":true,
            "labels":[
            ]
          }
        ]
-@@ -281,7 +281,7 @@
+@@ -211,7 +211,7 @@
+           "interfaceName":"eth-rt5",
+           "active":true,
+           "labels":[
+-            16060
++            30060
+           ]
+         }
+       ]
+@@ -290,7 +290,7 @@
            "interfaceName":"eth-rt5",
            "active":true,
            "labels":[
@@ -27,7 +45,7 @@
            ]
          }
        ]
-@@ -319,7 +319,7 @@
+@@ -328,7 +328,7 @@
            "interfaceName":"eth-rt5",
            "active":true,
            "labels":[
index ca495216ddd66d35844fc61c5cf403ed3d756051..57a57647a17ed5191beabcdfeaf9a337a761b905 100644 (file)
@@ -1,6 +1,15 @@
---- rt4/step5/show_ipv6_route.ref      2020-09-25 17:50:14.040592332 -0300
-+++ rt4/step6/show_ipv6_route.ref      2020-09-25 17:51:16.969413804 -0300
-@@ -84,7 +84,7 @@
+--- a/rt4/step5/show_ipv6_route.ref
++++ b/rt4/step6/show_ipv6_route.ref
+@@ -40,7 +40,7 @@
+           "interfaceName":"eth-rt5",
+           "active":true,
+           "labels":[
+-            16011
++            30011
+           ]
+         }
+       ]
+@@ -87,7 +87,7 @@
            "interfaceName":"eth-rt5",
            "active":true,
            "labels":[
              16021
            ]
          }
-@@ -116,7 +116,7 @@
+@@ -128,7 +128,7 @@
            "interfaceName":"eth-rt5",
            "active":true,
            "labels":[
 -            16031
 +            30031
            ]
-         },
-         {
+         }
+       ]
+@@ -198,7 +198,7 @@
+           "interfaceName":"eth-rt5",
+           "active":true,
+           "labels":[
+-            16061
++            30061
+           ]
+         }
+       ]
index 630e0419cf2a566eee9bcb0d0a2e0f6a23b29f29..94f87854d170252449791b20841eb95acbb562ff 100644 (file)
@@ -1,5 +1,23 @@
---- rt4/step5/show_mpls_table.ref      2020-09-25 17:50:11.488559034 -0300
-+++ rt4/step6/show_mpls_table.ref      2020-09-25 17:51:14.481381312 -0300
+--- a/rt4/step5/show_mpls_table.ref
++++ b/rt4/step6/show_mpls_table.ref
+@@ -25,7 +25,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16010,
++        "outLabel":30010,
+         "nexthop":"10.0.6.5"
+       }
+     ]
+@@ -56,7 +56,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16011,
++        "outLabel":30011,
+         "interface":"eth-rt5"
+       }
+     ]
 @@ -87,7 +87,7 @@
      "backupNexthops":[
        {
          "installed":true,
          "interface":"eth-rt5"
        }
+@@ -232,7 +232,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16060,
++        "outLabel":30060,
+         "nexthop":"10.0.6.5"
+       }
+     ]
+@@ -254,7 +254,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16061,
++        "outLabel":30061,
+         "interface":"eth-rt5"
+       }
+     ]
index 30e0dcf3c0c098ee98ebf9b8f35b2ff70f71d012..e54873d5ab5933a5584595df22907bdcbdb89070 100644 (file)
@@ -1,6 +1,6 @@
---- rt4/step6/show_ip_route.ref        2020-09-25 17:51:15.725397558 -0300
-+++ rt4/step7/show_ip_route.ref        2020-09-25 17:52:02.614010084 -0300
-@@ -158,9 +158,6 @@
+--- a/rt4/step6/show_ip_route.ref
++++ b/rt4/step7/show_ip_route.ref
+@@ -161,9 +161,6 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
+@@ -172,10 +169,7 @@
+           "ip":"10.0.7.6",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt6",
+-          "active":true,
+-          "labels":[
+-            16050
+-          ]
++          "active":true
+         }
+       ]
+     }
index 2606027d7514329b4d0c1c8b2126c2c6302a0778..92e08f99a065a869070a3ba0d0d6d1137de48b36 100644 (file)
@@ -1,6 +1,6 @@
---- rt4/step6/show_ipv6_route.ref      2020-09-25 17:51:16.969413804 -0300
-+++ rt4/step7/show_ipv6_route.ref      2020-09-25 17:52:03.854026287 -0300
-@@ -148,9 +148,6 @@
+--- a/rt4/step6/show_ipv6_route.ref
++++ b/rt4/step7/show_ipv6_route.ref
+@@ -151,9 +151,6 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
+@@ -161,10 +158,7 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt6",
+-          "active":true,
+-          "labels":[
+-            16051
+-          ]
++          "active":true
+         }
+       ]
+     }
index 5334cfd04860a5c0dd06baf16142b4167f4d2ea0..fb614ebf6a8a26e4b6f4f602c70b1da0449d965b 100644 (file)
@@ -1,5 +1,5 @@
---- rt4/step6/show_mpls_table.ref      2020-09-25 17:51:14.481381312 -0300
-+++ rt4/step7/show_mpls_table.ref      2020-09-25 17:52:01.385994037 -0300
+--- a/rt4/step6/show_mpls_table.ref
++++ b/rt4/step7/show_mpls_table.ref
 @@ -171,50 +171,6 @@
        }
      ]
@@ -21,7 +21,7 @@
 -    "backupNexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16050,
 -        "nexthop":"10.0.7.6"
 -      }
 -    ]
@@ -43,7 +43,7 @@
 -    "backupNexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16051,
 -        "interface":"eth-rt6"
 -      }
 -    ]
index b393970e423bb59081388897951360c62c80d743..252da6e76417b1ea49ed4f060957eb8d1eb289fb 100644 (file)
@@ -1,6 +1,6 @@
---- rt4/step7/show_ip_route.ref        2020-09-25 17:52:02.614010084 -0300
-+++ rt4/step8/show_ip_route.ref        2020-09-25 17:53:20.623029909 -0300
-@@ -158,6 +158,9 @@
+--- a/rt4/step7/show_ip_route.ref
++++ b/rt4/step8/show_ip_route.ref
+@@ -161,6 +161,9 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
+@@ -169,7 +172,10 @@
+           "ip":"10.0.7.6",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt6",
+-          "active":true
++          "active":true,
++          "labels":[
++            16050
++          ]
+         }
+       ]
+     }
index 8bad2edcf339857371c3f88e6f62323f7825431d..7057d2166a0cf24cf85c329a62ac6d3209fbe8e0 100644 (file)
@@ -1,6 +1,6 @@
---- rt4/step7/show_ipv6_route.ref      2020-09-25 17:52:03.854026287 -0300
-+++ rt4/step8/show_ipv6_route.ref      2020-09-25 17:53:21.843045865 -0300
-@@ -148,6 +148,9 @@
+--- a/rt4/step7/show_ipv6_route.ref
++++ b/rt4/step8/show_ipv6_route.ref
+@@ -151,6 +151,9 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
+@@ -158,7 +161,10 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt6",
+-          "active":true
++          "active":true,
++          "labels":[
++            16051
++          ]
+         }
+       ]
+     }
index d296dbdcafc70654dc66a99e95164e566a1d60bb..3dc4303b9b4d2f261a7dc33c8172779f778244b0 100644 (file)
@@ -1,5 +1,5 @@
---- rt4/step7/show_mpls_table.ref      2020-09-25 17:52:01.385994037 -0300
-+++ rt4/step8/show_mpls_table.ref      2020-09-25 17:53:19.371013534 -0300
+--- a/rt4/step7/show_mpls_table.ref
++++ b/rt4/step8/show_mpls_table.ref
 @@ -171,6 +171,50 @@
        }
      ]
@@ -21,7 +21,7 @@
 +    "backupNexthops":[
 +      {
 +        "type":"SR (IS-IS)",
-+        "outLabel":3,
++        "outLabel":16050,
 +        "nexthop":"10.0.7.6"
 +      }
 +    ]
@@ -43,7 +43,7 @@
 +    "backupNexthops":[
 +      {
 +        "type":"SR (IS-IS)",
-+        "outLabel":3,
++        "outLabel":16051,
 +        "interface":"eth-rt6"
 +      }
 +    ]
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..56f9cc534f95cd6c83e6fb0fc55e9c7b534d9c09 100644 (file)
@@ -0,0 +1,11 @@
+--- a/rt4/step8/show_ip_route.ref
++++ b/rt4/step9/show_ip_route.ref
+@@ -174,7 +174,7 @@
+           "interfaceName":"eth-rt6",
+           "active":true,
+           "labels":[
+-            16050
++            16500
+           ]
+         }
+       ]
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..41e552177a2f04d3c39f5f8c4344e72613343a94 100644 (file)
@@ -0,0 +1,11 @@
+--- a/rt4/step8/show_ipv6_route.ref
++++ b/rt4/step9/show_ipv6_route.ref
+@@ -163,7 +163,7 @@
+           "interfaceName":"eth-rt6",
+           "active":true,
+           "labels":[
+-            16051
++            16501
+           ]
+         }
+       ]
index 408cbfb0ba6a110c70f078390aaaee43a3afc6ac..627e292518fa88dc8d00185aa99c6116b449ec50 100644 (file)
@@ -1,5 +1,5 @@
---- rt4/step8/show_mpls_table.ref      2020-09-25 17:53:19.371013534 -0300
-+++ rt4/step9/show_mpls_table.ref      2020-09-25 17:54:37.064030042 -0300
+--- a/rt4/step8/show_mpls_table.ref
++++ b/rt4/step9/show_mpls_table.ref
 @@ -171,15 +171,15 @@
        }
      ]
          "backupIndex":[
            0
          ]
-@@ -189,19 +189,19 @@
+@@ -188,20 +188,20 @@
+     "backupNexthops":[
        {
          "type":"SR (IS-IS)",
-         "outLabel":3,
+-        "outLabel":16050,
 -        "nexthop":"10.0.7.6"
++        "outLabel":30060,
 +        "nexthop":"10.0.6.5"
        }
      ]
          "backupIndex":[
            0
          ]
-@@ -211,19 +211,19 @@
+@@ -210,20 +210,20 @@
+     "backupNexthops":[
        {
          "type":"SR (IS-IS)",
-         "outLabel":3,
+-        "outLabel":16051,
 -        "interface":"eth-rt6"
++        "outLabel":30061,
 +        "interface":"eth-rt5"
        }
      ]
          "backupIndex":[
            0
          ]
-@@ -233,19 +233,19 @@
+@@ -232,20 +232,20 @@
+     "backupNexthops":[
        {
          "type":"SR (IS-IS)",
-         "outLabel":3,
+-        "outLabel":30060,
 -        "nexthop":"10.0.6.5"
++        "outLabel":16500,
 +        "nexthop":"10.0.7.6"
        }
      ]
          "backupIndex":[
            0
          ]
-@@ -255,7 +255,7 @@
+@@ -254,8 +254,8 @@
+     "backupNexthops":[
        {
          "type":"SR (IS-IS)",
-         "outLabel":3,
+-        "outLabel":30061,
 -        "interface":"eth-rt5"
++        "outLabel":16501,
 +        "interface":"eth-rt6"
        }
      ]
index f747065f9c13c8eb2d71718706affc86caa5cf7b..93740e22e0c74506a2b8e227c99cc99f325abfce 100644 (file)
           "ip":"10.0.6.4",
           "afi":"ipv4",
           "interfaceName":"eth-rt4",
-          "active":true
+          "active":true,
+          "labels":[
+            16010
+          ]
         }
       ]
     }
           "ip":"10.0.8.6",
           "afi":"ipv4",
           "interfaceName":"eth-rt6",
-          "active":true
+          "active":true,
+          "labels":[
+            16040
+          ]
         }
       ]
     }
           "ip":"10.0.6.4",
           "afi":"ipv4",
           "interfaceName":"eth-rt4",
-          "active":true
+          "active":true,
+          "labels":[
+            16060
+          ]
         }
       ]
     }
index 6c0a5e0b9b19c5b40fe81ee888589d914e03a140..6dafa69adb8f59b1ffb4954ede5d722c5814a09e 100644 (file)
@@ -12,7 +12,7 @@
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt3-1",
+          "interfaceName":"eth-rt3-2",
           "active":true,
           "backupIndex":[
             0
@@ -24,7 +24,7 @@
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt3-2",
+          "interfaceName":"eth-rt3-1",
           "active":true,
           "backupIndex":[
             0
         {
           "afi":"ipv6",
           "interfaceName":"eth-rt4",
-          "active":true
+          "active":true,
+          "labels":[
+            16011
+          ]
         }
       ]
     }
@@ -65,7 +68,7 @@
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt3-1",
+          "interfaceName":"eth-rt3-2",
           "active":true,
           "labels":[
             16021
@@ -74,7 +77,7 @@
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt3-2",
+          "interfaceName":"eth-rt3-1",
           "active":true,
           "labels":[
             16021
@@ -96,7 +99,7 @@
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt3-1",
+          "interfaceName":"eth-rt3-2",
           "active":true,
           "backupIndex":[
             0
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt3-2",
+          "interfaceName":"eth-rt3-1",
           "active":true,
           "backupIndex":[
             0
         {
           "afi":"ipv6",
           "interfaceName":"eth-rt6",
-          "active":true
+          "active":true,
+          "labels":[
+            16041
+          ]
         }
       ]
     }
         {
           "afi":"ipv6",
           "interfaceName":"eth-rt4",
-          "active":true
+          "active":true,
+          "labels":[
+            16061
+          ]
         }
       ]
     }
index 2b70392adc08c65356c68dadcb2be0911323d633..0c5861b5e89d3a9176b0314be55f76750e51e25d 100644 (file)
@@ -25,7 +25,7 @@
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16010,
         "nexthop":"10.0.6.4"
       }
     ]
@@ -56,7 +56,7 @@
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16011,
         "interface":"eth-rt4"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16040,
         "nexthop":"10.0.8.6"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16041,
         "interface":"eth-rt6"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16060,
         "nexthop":"10.0.6.4"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16061,
         "interface":"eth-rt4"
       }
     ]
index 6402b51893a0b8fce1e1b237fe594adda020ac57..7545a31b9b050ad30997b920f587820fd2c58fed 100644 (file)
@@ -1,6 +1,18 @@
---- rt5/step3/show_ip_route.ref        2020-09-25 17:48:05.950922766 -0300
-+++ rt5/step4/show_ip_route.ref        2020-09-25 17:49:02.363657616 -0300
-@@ -81,10 +81,7 @@
+--- a/rt5/step3/show_ip_route.ref
++++ b/rt5/step4/show_ip_route.ref
+@@ -41,10 +41,7 @@
+           "ip":"10.0.6.4",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt4",
+-          "active":true,
+-          "labels":[
+-            16010
+-          ]
++          "active":true
+         }
+       ]
+     }
+@@ -84,10 +81,7 @@
            "ip":"10.0.6.4",
            "afi":"ipv4",
            "interfaceName":"eth-rt4",
@@ -12,7 +24,7 @@
          }
        ]
      }
-@@ -105,9 +102,6 @@
+@@ -108,9 +102,6 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt3-1",
            "active":true,
@@ -22,7 +34,7 @@
            "labels":[
              3
            ]
-@@ -118,25 +112,10 @@
+@@ -121,25 +112,10 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt3-2",
            "active":true,
@@ -48,7 +60,7 @@
        ]
      }
    ],
-@@ -158,9 +137,6 @@
+@@ -161,9 +137,6 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
-@@ -349,30 +325,13 @@
+@@ -172,10 +145,7 @@
+           "ip":"10.0.8.6",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt6",
+-          "active":true,
+-          "labels":[
+-            16040
+-          ]
++          "active":true
+         }
+       ]
+     }
+@@ -209,10 +179,7 @@
+           "ip":"10.0.6.4",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt4",
+-          "active":true,
+-          "labels":[
+-            16060
+-          ]
++          "active":true
+         }
+       ]
+     }
+@@ -358,30 +325,13 @@
          {
            "ip":"10.0.4.3",
            "afi":"ipv4",
          }
        ]
      }
-@@ -388,29 +347,12 @@
+@@ -397,29 +347,12 @@
            "ip":"10.0.4.3",
            "afi":"ipv4",
            "interfaceName":"eth-rt3-1",
index 7a0135bf04db548f1acac3eb4144b54efa647968..1de62bb58e18d5d1b6d6a464132cb68e6df7e516 100644 (file)
@@ -1,6 +1,18 @@
---- rt5/step3/show_ipv6_route.ref      2020-09-25 17:48:07.218939274 -0300
-+++ rt5/step4/show_ipv6_route.ref      2020-09-25 17:49:03.599673726 -0300
-@@ -57,10 +57,7 @@
+--- a/rt5/step3/show_ipv6_route.ref
++++ b/rt5/step4/show_ipv6_route.ref
+@@ -38,10 +38,7 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt4",
+-          "active":true,
+-          "labels":[
+-            16011
+-          ]
++          "active":true
+         }
+       ]
+     }
+@@ -60,10 +57,7 @@
            "fib":true,
            "afi":"ipv6",
            "interfaceName":"eth-rt4",
@@ -12,9 +24,9 @@
          },
          {
            "fib":true,
-@@ -98,9 +95,6 @@
+@@ -101,9 +95,6 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt3-1",
+           "interfaceName":"eth-rt3-2",
            "active":true,
 -          "backupIndex":[
 -            0
@@ -22,9 +34,9 @@
            "labels":[
              3
            ]
-@@ -110,24 +104,10 @@
+@@ -113,24 +104,10 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt3-2",
+           "interfaceName":"eth-rt3-1",
            "active":true,
 -          "backupIndex":[
 -            0
@@ -47,7 +59,7 @@
        ]
      }
    ],
-@@ -148,9 +128,6 @@
+@@ -151,9 +128,6 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
+@@ -161,10 +135,7 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt6",
+-          "active":true,
+-          "labels":[
+-            16041
+-          ]
++          "active":true
+         }
+       ]
+     }
+@@ -196,10 +167,7 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt4",
+-          "active":true,
+-          "labels":[
+-            16061
+-          ]
++          "active":true
+         }
+       ]
+     }
index 299dac76402bff79f614058c1ac59d8a2ca9a028..b3d525243052027d9c140a31f93c9590f819c4ed 100644 (file)
@@ -1,5 +1,23 @@
---- rt5/step3/show_mpls_table.ref      2020-09-25 17:48:04.626905528 -0300
-+++ rt5/step4/show_mpls_table.ref      2020-09-25 17:49:01.159641924 -0300
+--- a/rt5/step3/show_mpls_table.ref
++++ b/rt5/step4/show_mpls_table.ref
+@@ -25,7 +25,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16010,
++        "outLabel":3,
+         "nexthop":"10.0.6.4"
+       }
+     ]
+@@ -56,7 +56,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16011,
++        "outLabel":3,
+         "interface":"eth-rt4"
+       }
+     ]
 @@ -76,12 +76,6 @@
          "outLabel":16020,
          "installed":true,
 -    "backupNexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16040,
 -        "nexthop":"10.0.8.6"
 -      }
 -    ]
 -    "backupNexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16041,
 -        "interface":"eth-rt6"
 +        "interface":"eth-rt3-1"
        }
      ]
    },
+@@ -232,7 +150,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16060,
++        "outLabel":3,
+         "nexthop":"10.0.6.4"
+       }
+     ]
+@@ -254,7 +172,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16061,
++        "outLabel":3,
+         "interface":"eth-rt4"
+       }
+     ]
index 31f70b17a3c70030857da6d44e340ae293cfd89d..be5d83f4635739845242b4ad605ec4ae8ab17b95 100644 (file)
@@ -1,6 +1,18 @@
---- rt5/step4/show_ip_route.ref        2020-09-25 17:49:02.363657616 -0300
-+++ rt5/step5/show_ip_route.ref        2020-09-25 17:50:13.012578918 -0300
-@@ -81,7 +81,10 @@
+--- a/rt5/step4/show_ip_route.ref
++++ b/rt5/step5/show_ip_route.ref
+@@ -41,7 +41,10 @@
+           "ip":"10.0.6.4",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt4",
+-          "active":true
++          "active":true,
++          "labels":[
++            16010
++          ]
+         }
+       ]
+     }
+@@ -81,7 +84,10 @@
            "ip":"10.0.6.4",
            "afi":"ipv4",
            "interfaceName":"eth-rt4",
@@ -12,7 +24,7 @@
          }
        ]
      }
-@@ -102,6 +105,9 @@
+@@ -102,6 +108,9 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt3-1",
            "active":true,
@@ -22,7 +34,7 @@
            "labels":[
              3
            ]
-@@ -112,10 +118,25 @@
+@@ -112,10 +121,25 @@
            "afi":"ipv4",
            "interfaceName":"eth-rt3-2",
            "active":true,
@@ -48,7 +60,7 @@
        ]
      }
    ],
-@@ -137,6 +158,9 @@
+@@ -137,6 +161,9 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
-@@ -325,13 +349,30 @@
+@@ -145,7 +172,10 @@
+           "ip":"10.0.8.6",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt6",
+-          "active":true
++          "active":true,
++          "labels":[
++            16040
++          ]
+         }
+       ]
+     }
+@@ -179,7 +209,10 @@
+           "ip":"10.0.6.4",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt4",
+-          "active":true
++          "active":true,
++          "labels":[
++            16060
++          ]
+         }
+       ]
+     }
+@@ -325,13 +358,30 @@
          {
            "ip":"10.0.4.3",
            "afi":"ipv4",
          }
        ]
      }
-@@ -347,12 +388,29 @@
+@@ -347,12 +397,29 @@
            "ip":"10.0.4.3",
            "afi":"ipv4",
            "interfaceName":"eth-rt3-1",
index 59d9755e183e5a45d2e48d290a37d115d5b402ff..a856019622d47e25c6817ab6efb21a093e7ca915 100644 (file)
@@ -1,6 +1,18 @@
---- rt5/step4/show_ipv6_route.ref      2020-09-25 17:49:03.599673726 -0300
-+++ rt5/step5/show_ipv6_route.ref      2020-09-25 17:50:14.248595046 -0300
-@@ -57,7 +57,10 @@
+--- a/rt5/step4/show_ipv6_route.ref
++++ b/rt5/step5/show_ipv6_route.ref
+@@ -38,7 +38,10 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt4",
+-          "active":true
++          "active":true,
++          "labels":[
++            16011
++          ]
+         }
+       ]
+     }
+@@ -57,7 +60,10 @@
            "fib":true,
            "afi":"ipv6",
            "interfaceName":"eth-rt4",
@@ -12,9 +24,9 @@
          },
          {
            "fib":true,
-@@ -95,6 +98,9 @@
+@@ -95,6 +101,9 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt3-1",
+           "interfaceName":"eth-rt3-2",
            "active":true,
 +          "backupIndex":[
 +            0
@@ -22,9 +34,9 @@
            "labels":[
              3
            ]
-@@ -104,10 +110,24 @@
+@@ -104,10 +113,24 @@
            "afi":"ipv6",
-           "interfaceName":"eth-rt3-2",
+           "interfaceName":"eth-rt3-1",
            "active":true,
 +          "backupIndex":[
 +            0
@@ -47,7 +59,7 @@
        ]
      }
    ],
-@@ -128,6 +148,9 @@
+@@ -128,6 +151,9 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
+@@ -135,7 +161,10 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt6",
+-          "active":true
++          "active":true,
++          "labels":[
++            16041
++          ]
+         }
+       ]
+     }
+@@ -167,7 +196,10 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt4",
+-          "active":true
++          "active":true,
++          "labels":[
++            16061
++          ]
+         }
+       ]
+     }
index 669c07e3447289a2c9699686897553d51adeea49..74caa8620e6152c3ffbe63eb2ca860467e192063 100644 (file)
@@ -1,5 +1,23 @@
---- rt5/step4/show_mpls_table.ref      2020-09-25 17:49:01.159641924 -0300
-+++ rt5/step5/show_mpls_table.ref      2020-09-25 17:50:11.696561748 -0300
+--- a/rt5/step4/show_mpls_table.ref
++++ b/rt5/step5/show_mpls_table.ref
+@@ -25,7 +25,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":3,
++        "outLabel":16010,
+         "nexthop":"10.0.6.4"
+       }
+     ]
+@@ -56,7 +56,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":3,
++        "outLabel":16011,
+         "interface":"eth-rt4"
+       }
+     ]
 @@ -69,6 +69,12 @@
          "type":"SR (IS-IS)",
          "outLabel":16020,
 +    "backupNexthops":[
 +      {
 +        "type":"SR (IS-IS)",
-+        "outLabel":3,
++        "outLabel":16040,
 +        "nexthop":"10.0.8.6"
 +      }
 +    ]
 +    "backupNexthops":[
 +      {
 +        "type":"SR (IS-IS)",
-+        "outLabel":3,
++        "outLabel":16041,
 +        "interface":"eth-rt6"
        }
      ]
    },
+@@ -150,7 +232,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":3,
++        "outLabel":16060,
+         "nexthop":"10.0.6.4"
+       }
+     ]
+@@ -172,7 +254,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":3,
++        "outLabel":16061,
+         "interface":"eth-rt4"
+       }
+     ]
index a4f82cbf1056ed9205903310f8ef3c431cfcfacc..2883c046fd50af157339f9caf648ccc293697e0c 100644 (file)
@@ -1,5 +1,5 @@
---- rt5/step5/show_mpls_table.ref      2020-09-25 17:50:11.696561748 -0300
-+++ rt5/step6/show_mpls_table.ref      2020-09-25 17:51:14.685383977 -0300
+--- a/rt5/step5/show_mpls_table.ref
++++ b/rt5/step6/show_mpls_table.ref
 @@ -1,6 +1,6 @@
  {
 -  "16010":{
index 5bcef4c2f6df604251fda0ec7fb5320f5e9221a6..b9b43c41392705cd485f0ae637d3d5f9b2509d71 100644 (file)
           "ip":"10.0.8.5",
           "afi":"ipv4",
           "interfaceName":"eth-rt5",
-          "active":true
+          "active":true,
+          "labels":[
+            16020
+          ]
         }
       ]
     }
           "ip":"10.0.7.4",
           "afi":"ipv4",
           "interfaceName":"eth-rt4",
-          "active":true
+          "active":true,
+          "labels":[
+            16030
+          ]
         }
       ]
     }
           "ip":"10.0.8.5",
           "afi":"ipv4",
           "interfaceName":"eth-rt5",
-          "active":true
+          "active":true,
+          "labels":[
+            16040
+          ]
         }
       ]
     }
           "ip":"10.0.7.4",
           "afi":"ipv4",
           "interfaceName":"eth-rt4",
-          "active":true
+          "active":true,
+          "labels":[
+            16050
+          ]
         }
       ]
     }
index 8294b071367228ff8e2d1cdd3c0d460ddf50c4da..1b1942939ddc8c07770162fe6e1648713590e1b9 100644 (file)
@@ -12,7 +12,7 @@
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt5",
+          "interfaceName":"eth-rt4",
           "active":true,
           "labels":[
             16011
@@ -21,7 +21,7 @@
         {
           "fib":true,
           "afi":"ipv6",
-          "interfaceName":"eth-rt4",
+          "interfaceName":"eth-rt5",
           "active":true,
           "labels":[
             16011
         {
           "afi":"ipv6",
           "interfaceName":"eth-rt5",
-          "active":true
+          "active":true,
+          "labels":[
+            16021
+          ]
         }
       ]
     }
         {
           "afi":"ipv6",
           "interfaceName":"eth-rt4",
-          "active":true
+          "active":true,
+          "labels":[
+            16031
+          ]
         }
       ]
     }
         {
           "afi":"ipv6",
           "interfaceName":"eth-rt5",
-          "active":true
+          "active":true,
+          "labels":[
+            16041
+          ]
         }
       ]
     }
         {
           "afi":"ipv6",
           "interfaceName":"eth-rt4",
-          "active":true
+          "active":true,
+          "labels":[
+            16051
+          ]
         }
       ]
     }
index 33dbf592047f45575986580e3a0db55b5c816ed0..5b52a16f48df8e9c4d75608823180f1346aec6dc 100644 (file)
@@ -7,13 +7,13 @@
         "type":"SR (IS-IS)",
         "outLabel":16010,
         "installed":true,
-        "nexthop":"10.0.7.4"
+        "nexthop":"10.0.8.5"
       },
       {
         "type":"SR (IS-IS)",
         "outLabel":16010,
         "installed":true,
-        "nexthop":"10.0.8.5"
+        "nexthop":"10.0.7.4"
       }
     ]
   },
         "type":"SR (IS-IS)",
         "outLabel":16011,
         "installed":true,
-        "interface":"eth-rt4"
+        "interface":"eth-rt5"
       },
       {
         "type":"SR (IS-IS)",
         "outLabel":16011,
         "installed":true,
-        "interface":"eth-rt5"
+        "interface":"eth-rt4"
       }
     ]
   },
@@ -52,7 +52,7 @@
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16020,
         "nexthop":"10.0.8.5"
       }
     ]
@@ -74,7 +74,7 @@
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16021,
         "interface":"eth-rt5"
       }
     ]
@@ -96,7 +96,7 @@
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16030,
         "nexthop":"10.0.7.4"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16031,
         "interface":"eth-rt4"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16040,
         "nexthop":"10.0.8.5"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16041,
         "interface":"eth-rt5"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16050,
         "nexthop":"10.0.7.4"
       }
     ]
     "backupNexthops":[
       {
         "type":"SR (IS-IS)",
-        "outLabel":3,
+        "outLabel":16051,
         "interface":"eth-rt4"
       }
     ]
index 04adaefe784b287ba50ca5ccc7efe335408c8d47..7c2f00419ab04d172c68f71e1bcb052647308877 100644 (file)
@@ -1,5 +1,5 @@
---- rt6/step3/show_ip_route.ref        2020-09-25 17:48:06.154925422 -0300
-+++ rt6/step4/show_ip_route.ref        2020-09-25 17:49:02.583660484 -0300
+--- a/rt6/step3/show_ip_route.ref
++++ b/rt6/step4/show_ip_route.ref
 @@ -14,10 +14,7 @@
            "ip":"10.0.7.4",
            "afi":"ipv4",
            ]
          }
        ],
-@@ -118,9 +112,6 @@
+@@ -98,10 +92,7 @@
+           "ip":"10.0.7.4",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt4",
+-          "active":true,
+-          "labels":[
+-            16030
+-          ]
++          "active":true
+         }
+       ]
+     }
+@@ -124,9 +115,6 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
+@@ -135,10 +123,7 @@
+           "ip":"10.0.8.5",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt5",
+-          "active":true,
+-          "labels":[
+-            16040
+-          ]
++          "active":true
+         }
+       ]
+     }
+@@ -172,10 +157,7 @@
+           "ip":"10.0.7.4",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt4",
+-          "active":true,
+-          "labels":[
+-            16050
+-          ]
++          "active":true
+         }
+       ]
+     }
index 20aa1ec83b0a41684ebcb3c2401a1e033f464339..70f872e9de36e3f9024122e355d9044033ad2a28 100644 (file)
@@ -1,6 +1,6 @@
---- rt6/step3/show_ipv6_route.ref      2020-09-25 17:48:07.434942087 -0300
-+++ rt6/step4/show_ipv6_route.ref      2020-09-25 17:49:03.847676958 -0300
-@@ -22,10 +22,7 @@
+--- a/rt6/step3/show_ipv6_route.ref
++++ b/rt6/step4/show_ipv6_route.ref
+@@ -13,10 +13,7 @@
            "fib":true,
            "afi":"ipv6",
            "interfaceName":"eth-rt4",
@@ -9,9 +9,9 @@
 -            16011
 -          ]
 +          "active":true
-         }
-       ]
-     }
+         },
+         {
+           "fib":true,
 @@ -47,9 +44,6 @@
            "active":true,
            "backupIndex":[
            ]
          }
        ],
-@@ -111,9 +105,6 @@
+@@ -92,10 +86,7 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt4",
+-          "active":true,
+-          "labels":[
+-            16031
+-          ]
++          "active":true
+         }
+       ]
+     }
+@@ -117,9 +108,6 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
+@@ -127,10 +115,7 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt5",
+-          "active":true,
+-          "labels":[
+-            16041
+-          ]
++          "active":true
+         }
+       ]
+     }
+@@ -162,10 +147,7 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt4",
+-          "active":true,
+-          "labels":[
+-            16051
+-          ]
++          "active":true
+         }
+       ]
+     }
index 3f24547f6d547f40eb8e6e81c22ee4633f7bcbbd..c191763a73f788828ddb7f71bd77729d5cd26a72 100644 (file)
@@ -1,35 +1,49 @@
---- rt6/step3/show_mpls_table.ref      2020-09-25 17:48:04.842908340 -0300
-+++ rt6/step4/show_mpls_table.ref      2020-09-25 17:49:01.363644584 -0300
-@@ -7,12 +7,6 @@
-         "type":"SR (IS-IS)",
+--- a/rt6/step3/show_mpls_table.ref
++++ b/rt6/step4/show_mpls_table.ref
+@@ -8,12 +8,6 @@
          "outLabel":16010,
          "installed":true,
--        "nexthop":"10.0.7.4"
+         "nexthop":"10.0.8.5"
 -      },
 -      {
 -        "type":"SR (IS-IS)",
 -        "outLabel":16010,
 -        "installed":true,
-         "nexthop":"10.0.8.5"
+-        "nexthop":"10.0.7.4"
        }
      ]
-@@ -25,12 +19,6 @@
-         "type":"SR (IS-IS)",
+   },
+@@ -26,12 +20,6 @@
          "outLabel":16011,
          "installed":true,
--        "interface":"eth-rt4"
+         "interface":"eth-rt5"
 -      },
 -      {
 -        "type":"SR (IS-IS)",
 -        "outLabel":16011,
 -        "installed":true,
-         "interface":"eth-rt5"
+-        "interface":"eth-rt4"
        }
      ]
-@@ -123,50 +111,6 @@
+   },
+@@ -96,7 +84,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16030,
++        "outLabel":3,
+         "nexthop":"10.0.7.4"
        }
      ]
-   },
+@@ -118,52 +106,8 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16031,
+-        "interface":"eth-rt4"
+-      }
+-    ]
+-  },
 -  "16040":{
 -    "inLabel":16040,
 -    "installed":true,
@@ -47,7 +61,7 @@
 -    "backupNexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16040,
 -        "nexthop":"10.0.8.5"
 -      }
 -    ]
@@ -58,7 +72,7 @@
 -    "nexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+         "outLabel":3,
 -        "installed":true,
 -        "interface":"eth-rt4",
 -        "backupIndex":[
 -    "backupNexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16041,
 -        "interface":"eth-rt5"
--      }
--    ]
--  },
-   "16050":{
-     "inLabel":16050,
-     "installed":true,
++        "interface":"eth-rt4"
+       }
+     ]
+   },
+@@ -184,7 +128,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16050,
++        "outLabel":3,
+         "nexthop":"10.0.7.4"
+       }
+     ]
+@@ -206,7 +150,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16051,
++        "outLabel":3,
+         "interface":"eth-rt4"
+       }
+     ]
index 9f73a2904e91ae1fab90a92239204c9ab713dcd2..9f017d24925b27dbb6c57ebd1acb420389083641 100644 (file)
@@ -1,5 +1,5 @@
---- rt6/step4/show_ip_route.ref        2020-09-25 17:49:02.583660484 -0300
-+++ rt6/step5/show_ip_route.ref        2020-09-25 17:50:13.220581632 -0300
+--- a/rt6/step4/show_ip_route.ref
++++ b/rt6/step5/show_ip_route.ref
 @@ -14,7 +14,10 @@
            "ip":"10.0.7.4",
            "afi":"ipv4",
            ]
          }
        ],
-@@ -112,6 +118,9 @@
+@@ -92,7 +98,10 @@
+           "ip":"10.0.7.4",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt4",
+-          "active":true
++          "active":true,
++          "labels":[
++            16030
++          ]
+         }
+       ]
+     }
+@@ -115,6 +124,9 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
+@@ -123,7 +135,10 @@
+           "ip":"10.0.8.5",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt5",
+-          "active":true
++          "active":true,
++          "labels":[
++            16040
++          ]
+         }
+       ]
+     }
+@@ -157,7 +172,10 @@
+           "ip":"10.0.7.4",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt4",
+-          "active":true
++          "active":true,
++          "labels":[
++            16050
++          ]
+         }
+       ]
+     }
index c9358d45b2a2cf1fbaa15b75df8565fa9af073fb..1209504e9425bdcd15f523224c0fc8c7bb724729 100644 (file)
@@ -1,6 +1,6 @@
---- rt6/step4/show_ipv6_route.ref      2020-09-25 17:49:03.847676958 -0300
-+++ rt6/step5/show_ipv6_route.ref      2020-09-25 17:50:14.456597760 -0300
-@@ -22,7 +22,10 @@
+--- a/rt6/step4/show_ipv6_route.ref
++++ b/rt6/step5/show_ipv6_route.ref
+@@ -13,7 +13,10 @@
            "fib":true,
            "afi":"ipv6",
            "interfaceName":"eth-rt4",
@@ -9,9 +9,9 @@
 +          "labels":[
 +            16011
 +          ]
-         }
-       ]
-     }
+         },
+         {
+           "fib":true,
 @@ -44,6 +47,9 @@
            "active":true,
            "backupIndex":[
            ]
          }
        ],
-@@ -105,6 +111,9 @@
+@@ -86,7 +92,10 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt4",
+-          "active":true
++          "active":true,
++          "labels":[
++            16031
++          ]
+         }
+       ]
+     }
+@@ -108,6 +117,9 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
+@@ -115,7 +127,10 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt5",
+-          "active":true
++          "active":true,
++          "labels":[
++            16041
++          ]
+         }
+       ]
+     }
+@@ -147,7 +162,10 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt4",
+-          "active":true
++          "active":true,
++          "labels":[
++            16051
++          ]
+         }
+       ]
+     }
index c9d67955ef456088c2fff72869809dc06b9b0c77..abf7c2a32d73c19b58f57134aad7994d0466b146 100644 (file)
@@ -1,5 +1,5 @@
---- rt6/step4/show_mpls_table.ref      2020-09-25 17:49:01.363644584 -0300
-+++ rt6/step5/show_mpls_table.ref      2020-09-25 17:50:11.904564461 -0300
+--- a/rt6/step4/show_mpls_table.ref
++++ b/rt6/step5/show_mpls_table.ref
 @@ -7,6 +7,12 @@
          "type":"SR (IS-IS)",
          "outLabel":16010,
          "interface":"eth-rt5"
        }
      ]
-@@ -111,6 +123,50 @@
+@@ -84,7 +96,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":3,
++        "outLabel":16030,
+         "nexthop":"10.0.7.4"
+       }
+     ]
+@@ -106,11 +118,55 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":3,
++        "outLabel":16031,
+         "interface":"eth-rt4"
        }
      ]
    },
@@ -47,7 +62,7 @@
 +    "backupNexthops":[
 +      {
 +        "type":"SR (IS-IS)",
-+        "outLabel":3,
++        "outLabel":16040,
 +        "nexthop":"10.0.8.5"
 +      }
 +    ]
@@ -69,7 +84,7 @@
 +    "backupNexthops":[
 +      {
 +        "type":"SR (IS-IS)",
-+        "outLabel":3,
++        "outLabel":16041,
 +        "interface":"eth-rt5"
 +      }
 +    ]
    "16050":{
      "inLabel":16050,
      "installed":true,
+@@ -128,7 +184,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":3,
++        "outLabel":16050,
+         "nexthop":"10.0.7.4"
+       }
+     ]
+@@ -150,7 +206,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":3,
++        "outLabel":16051,
+         "interface":"eth-rt4"
+       }
+     ]
index 527ec74958f3911fe29d7852226629d065bf4e67..f318f95e212bcb0eefa6b331aaebab1f39319ea8 100644 (file)
@@ -1,5 +1,5 @@
---- rt6/step5/show_ip_route.ref        2020-09-25 17:50:13.220581632 -0300
-+++ rt6/step6/show_ip_route.ref        2020-09-25 17:51:16.137402938 -0300
+--- a/rt6/step5/show_ip_route.ref
++++ b/rt6/step6/show_ip_route.ref
 @@ -26,7 +26,7 @@
            "interfaceName":"eth-rt5",
            "active":true,
@@ -9,7 +9,16 @@
            ]
          }
        ]
-@@ -86,7 +86,7 @@
+@@ -63,7 +63,7 @@
+           "interfaceName":"eth-rt5",
+           "active":true,
+           "labels":[
+-            16020
++            30020
+           ]
+         }
+       ]
+@@ -89,7 +89,7 @@
              0
            ],
            "labels":[
            ]
          }
        ],
+@@ -137,7 +137,7 @@
+           "interfaceName":"eth-rt5",
+           "active":true,
+           "labels":[
+-            16040
++            30040
+           ]
+         }
+       ]
index 7b8f8022f24534a9eaa3f5250c5b74362ce2a4f2..9208491fc824f3d168495a3502b4829e427ddaad 100644 (file)
@@ -1,15 +1,24 @@
---- rt6/step5/show_ipv6_route.ref      2020-09-25 17:50:14.456597760 -0300
-+++ rt6/step6/show_ipv6_route.ref      2020-09-25 17:51:17.401419446 -0300
-@@ -15,7 +15,7 @@
+--- a/rt6/step5/show_ipv6_route.ref
++++ b/rt6/step6/show_ipv6_route.ref
+@@ -24,7 +24,7 @@
            "interfaceName":"eth-rt5",
            "active":true,
            "labels":[
 -            16011
 +            30011
            ]
-         },
-         {
-@@ -81,7 +81,7 @@
+         }
+       ]
+@@ -59,7 +59,7 @@
+           "interfaceName":"eth-rt5",
+           "active":true,
+           "labels":[
+-            16021
++            30021
+           ]
+         }
+       ]
+@@ -84,7 +84,7 @@
              0
            ],
            "labels":[
            ]
          }
        ],
+@@ -129,7 +129,7 @@
+           "interfaceName":"eth-rt5",
+           "active":true,
+           "labels":[
+-            16041
++            30041
+           ]
+         }
+       ]
index edd5afeeb80aa61113041086b929a0a63e9878ce..aee8969deddc27c4be5eae0c52d4ef38ce3b6e08 100644 (file)
@@ -1,5 +1,5 @@
---- rt6/step5/show_mpls_table.ref      2020-09-25 17:50:11.904564461 -0300
-+++ rt6/step6/show_mpls_table.ref      2020-09-25 17:51:14.893386692 -0300
+--- a/rt6/step5/show_mpls_table.ref
++++ b/rt6/step6/show_mpls_table.ref
 @@ -11,7 +11,7 @@
        },
        {
          "installed":true,
          "interface":"eth-rt5"
        }
+@@ -52,7 +52,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16020,
++        "outLabel":30020,
+         "nexthop":"10.0.8.5"
+       }
+     ]
+@@ -74,7 +74,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16021,
++        "outLabel":30021,
+         "interface":"eth-rt5"
+       }
+     ]
 @@ -85,7 +85,7 @@
      "nexthops":[
        {
          "installed":true,
          "interface":"eth-rt5",
          "backupIndex":[
+@@ -140,7 +140,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16040,
++        "outLabel":30040,
+         "nexthop":"10.0.8.5"
+       }
+     ]
+@@ -162,7 +162,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16041,
++        "outLabel":30041,
+         "interface":"eth-rt5"
+       }
+     ]
index 7553dd22e5794ede0967d1b92205550913abecc0..0e6c3ff5cd549680e35c0c3feac8ebd05c21edf4 100644 (file)
@@ -1,6 +1,6 @@
---- rt6/step6/show_ip_route.ref        2020-09-25 17:51:16.137402938 -0300
-+++ rt6/step7/show_ip_route.ref        2020-09-25 17:52:03.018015363 -0300
-@@ -152,9 +152,6 @@
+--- a/rt6/step6/show_ip_route.ref
++++ b/rt6/step7/show_ip_route.ref
+@@ -161,9 +161,6 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
+@@ -172,10 +169,7 @@
+           "ip":"10.0.7.4",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt4",
+-          "active":true,
+-          "labels":[
+-            16050
+-          ]
++          "active":true
+         }
+       ]
+     }
index b56890de0fcd53c80964e5bff80007741b5c8e1b..2fe46c82658a91b6da172cd76232a9c19588ea4a 100644 (file)
@@ -1,6 +1,6 @@
---- rt6/step6/show_ipv6_route.ref      2020-09-25 17:51:17.401419446 -0300
-+++ rt6/step7/show_ipv6_route.ref      2020-09-25 17:52:04.270031723 -0300
-@@ -143,9 +143,6 @@
+--- a/rt6/step6/show_ipv6_route.ref
++++ b/rt6/step7/show_ipv6_route.ref
+@@ -152,9 +152,6 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
+@@ -162,10 +159,7 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt4",
+-          "active":true,
+-          "labels":[
+-            16051
+-          ]
++          "active":true
+         }
+       ]
+     }
index ff043fb0bf309fe4357f6165b44d61837e12690f..179a4f460b2a5654d7a8d7aa79a67c53607233ee 100644 (file)
@@ -1,5 +1,5 @@
---- rt6/step6/show_mpls_table.ref      2020-09-25 17:51:14.893386692 -0300
-+++ rt6/step7/show_mpls_table.ref      2020-09-25 17:52:01.809999577 -0300
+--- a/rt6/step6/show_mpls_table.ref
++++ b/rt6/step7/show_mpls_table.ref
 @@ -166,49 +166,5 @@
          "interface":"eth-rt5"
        }
@@ -22,7 +22,7 @@
 -    "backupNexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16050,
 -        "nexthop":"10.0.7.4"
 -      }
 -    ]
@@ -44,7 +44,7 @@
 -    "backupNexthops":[
 -      {
 -        "type":"SR (IS-IS)",
--        "outLabel":3,
+-        "outLabel":16051,
 -        "interface":"eth-rt4"
 -      }
 -    ]
index d0b25bffa31ce95eef45c633ff947e56fc9f84f5..9d5c440a2215d875efce3bcae5ec87bd727bb295 100644 (file)
@@ -1,6 +1,6 @@
---- rt6/step7/show_ip_route.ref        2020-09-25 17:52:03.018015363 -0300
-+++ rt6/step8/show_ip_route.ref        2020-09-25 17:53:21.035035298 -0300
-@@ -152,6 +152,9 @@
+--- a/rt6/step7/show_ip_route.ref
++++ b/rt6/step8/show_ip_route.ref
+@@ -161,6 +161,9 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
+@@ -169,7 +172,10 @@
+           "ip":"10.0.7.4",
+           "afi":"ipv4",
+           "interfaceName":"eth-rt4",
+-          "active":true
++          "active":true,
++          "labels":[
++            16050
++          ]
+         }
+       ]
+     }
index 203175510c0f28e496278607c3b4822f362cea70..21cab20a470a795eea03cfbc73954f06a87911d7 100644 (file)
@@ -1,6 +1,6 @@
---- rt6/step7/show_ipv6_route.ref      2020-09-25 17:52:04.270031723 -0300
-+++ rt6/step8/show_ipv6_route.ref      2020-09-25 17:53:22.239051045 -0300
-@@ -143,6 +143,9 @@
+--- a/rt6/step7/show_ipv6_route.ref
++++ b/rt6/step8/show_ipv6_route.ref
+@@ -152,6 +152,9 @@
            "active":true,
            "backupIndex":[
              0
            ]
          }
        ],
+@@ -159,7 +162,10 @@
+         {
+           "afi":"ipv6",
+           "interfaceName":"eth-rt4",
+-          "active":true
++          "active":true,
++          "labels":[
++            16051
++          ]
+         }
+       ]
+     }
index 535f30bf358329bdac5b94d24c52c6b756fdf21e..760c5542cb7ed74c78a6359727bee758ac6ab00d 100644 (file)
@@ -1,5 +1,5 @@
---- rt6/step7/show_mpls_table.ref      2020-09-25 17:52:01.809999577 -0300
-+++ rt6/step8/show_mpls_table.ref      2020-09-25 17:53:19.799019132 -0300
+--- a/rt6/step7/show_mpls_table.ref
++++ b/rt6/step8/show_mpls_table.ref
 @@ -166,5 +166,49 @@
          "interface":"eth-rt5"
        }
@@ -22,7 +22,7 @@
 +    "backupNexthops":[
 +      {
 +        "type":"SR (IS-IS)",
-+        "outLabel":3,
++        "outLabel":16050,
 +        "nexthop":"10.0.7.4"
 +      }
 +    ]
@@ -44,7 +44,7 @@
 +    "backupNexthops":[
 +      {
 +        "type":"SR (IS-IS)",
-+        "outLabel":3,
++        "outLabel":16051,
 +        "interface":"eth-rt4"
 +      }
 +    ]
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ee296470c0ccd0fc8db798e4a27bca5bf58757a5 100644 (file)
@@ -0,0 +1,11 @@
+--- a/rt6/step8/show_ip_route.ref
++++ b/rt6/step9/show_ip_route.ref
+@@ -174,7 +174,7 @@
+           "interfaceName":"eth-rt4",
+           "active":true,
+           "labels":[
+-            16050
++            16500
+           ]
+         }
+       ]
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bebca4dcf18962c4787e681ef8e629a98d4675ca 100644 (file)
@@ -0,0 +1,11 @@
+--- a/rt6/step8/show_ipv6_route.ref
++++ b/rt6/step9/show_ipv6_route.ref
+@@ -164,7 +164,7 @@
+           "interfaceName":"eth-rt4",
+           "active":true,
+           "labels":[
+-            16051
++            16501
+           ]
+         }
+       ]
index b6e5396554a2fb338bb6a45b0ec3f6b6eede229f..57347d15beed5dfdf50d6397d2d95490cd7e8924 100644 (file)
@@ -1,5 +1,5 @@
---- rt6/step8/show_mpls_table.ref      2020-09-25 17:53:19.799019132 -0300
-+++ rt6/step9/show_mpls_table.ref      2020-09-25 17:54:37.492035644 -0300
+--- a/rt6/step8/show_mpls_table.ref
++++ b/rt6/step9/show_mpls_table.ref
 @@ -167,8 +167,8 @@
        }
      ]
      "installed":true,
      "nexthops":[
        {
-@@ -189,8 +189,8 @@
+@@ -184,13 +184,13 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16050,
++        "outLabel":16500,
+         "nexthop":"10.0.7.4"
        }
      ]
    },
      "installed":true,
      "nexthops":[
        {
+@@ -206,7 +206,7 @@
+     "backupNexthops":[
+       {
+         "type":"SR (IS-IS)",
+-        "outLabel":16051,
++        "outLabel":16501,
+         "interface":"eth-rt4"
+       }
+     ]
index 6bc097b0e7bdcf5fe4994f4f3ad8f998703abdba..83751fabcd5103ca15c6a5f27c450b0c203a8945 100755 (executable)
@@ -74,7 +74,7 @@ from functools import partial
 
 # Save the Current Working Directory to find configuration files.
 CWD = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.join(CWD, '../'))
+sys.path.append(os.path.join(CWD, "../"))
 
 # pylint: disable=C0413
 # Import topogen and topotest helpers
@@ -88,8 +88,10 @@ from mininet.topo import Topo
 # Global multi-dimensional dictionary containing all expected outputs
 outputs = {}
 
+
 class TemplateTopo(Topo):
     "Test topology builder"
+
     def build(self, *_args, **_opts):
         "Build function"
         tgen = get_topogen(self)
@@ -97,80 +99,85 @@ class TemplateTopo(Topo):
         #
         # Define FRR Routers
         #
-        for router in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+        for router in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
             tgen.add_router(router)
 
         #
         # Define connections
         #
-        switch = tgen.add_switch('s1')
-        switch.add_link(tgen.gears['rt1'], nodeif="eth-sw1")
-        switch.add_link(tgen.gears['rt2'], nodeif="eth-sw1")
-        switch.add_link(tgen.gears['rt3'], nodeif="eth-sw1")
+        switch = tgen.add_switch("s1")
+        switch.add_link(tgen.gears["rt1"], nodeif="eth-sw1")
+        switch.add_link(tgen.gears["rt2"], nodeif="eth-sw1")
+        switch.add_link(tgen.gears["rt3"], nodeif="eth-sw1")
 
-        switch = tgen.add_switch('s2')
-        switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-1")
-        switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-1")
+        switch = tgen.add_switch("s2")
+        switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-1")
+        switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-1")
 
-        switch = tgen.add_switch('s3')
-        switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-2")
-        switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-2")
+        switch = tgen.add_switch("s3")
+        switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-2")
+        switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-2")
 
-        switch = tgen.add_switch('s4')
-        switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-1")
-        switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-1")
+        switch = tgen.add_switch("s4")
+        switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5-1")
+        switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3-1")
 
-        switch = tgen.add_switch('s5')
-        switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-2")
-        switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-2")
+        switch = tgen.add_switch("s5")
+        switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5-2")
+        switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3-2")
 
-        switch = tgen.add_switch('s6')
-        switch.add_link(tgen.gears['rt4'], nodeif="eth-rt5")
-        switch.add_link(tgen.gears['rt5'], nodeif="eth-rt4")
+        switch = tgen.add_switch("s6")
+        switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5")
+        switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4")
 
-        switch = tgen.add_switch('s7')
-        switch.add_link(tgen.gears['rt4'], nodeif="eth-rt6")
-        switch.add_link(tgen.gears['rt6'], nodeif="eth-rt4")
+        switch = tgen.add_switch("s7")
+        switch.add_link(tgen.gears["rt4"], nodeif="eth-rt6")
+        switch.add_link(tgen.gears["rt6"], nodeif="eth-rt4")
 
-        switch = tgen.add_switch('s8')
-        switch.add_link(tgen.gears['rt5'], nodeif="eth-rt6")
-        switch.add_link(tgen.gears['rt6'], nodeif="eth-rt5")
+        switch = tgen.add_switch("s8")
+        switch.add_link(tgen.gears["rt5"], nodeif="eth-rt6")
+        switch.add_link(tgen.gears["rt6"], nodeif="eth-rt5")
 
         #
         # Populate multi-dimensional dictionary containing all expected outputs
         #
-        files = ["show_ip_route.ref",
-                 "show_ipv6_route.ref",
-                 "show_mpls_table.ref",
-                 "show_yang_interface_isis_adjacencies.ref"]
-        for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+        files = [
+            "show_ip_route.ref",
+            "show_ipv6_route.ref",
+            "show_mpls_table.ref",
+            "show_yang_interface_isis_adjacencies.ref",
+        ]
+        for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
             outputs[rname] = {}
             for step in range(1, 9 + 1):
                 outputs[rname][step] = {}
                 for file in files:
                     if step == 1:
                         # Get snapshots relative to the expected initial network convergence
-                        filename = '{}/{}/step{}/{}'.format(CWD, rname, step, file)
+                        filename = "{}/{}/step{}/{}".format(CWD, rname, step, file)
                         outputs[rname][step][file] = open(filename).read()
                     else:
                         if file == "show_yang_interface_isis_adjacencies.ref":
                             continue
 
                         # Get diff relative to the previous step
-                        filename = '{}/{}/step{}/{}.diff'.format(CWD, rname, step, file)
+                        filename = "{}/{}/step{}/{}.diff".format(CWD, rname, step, file)
 
                         # Create temporary files in order to apply the diff
                         f_in = tempfile.NamedTemporaryFile()
                         f_in.write(outputs[rname][step - 1][file])
                         f_in.flush()
                         f_out = tempfile.NamedTemporaryFile()
-                        os.system("patch -s -o %s %s %s" %(f_out.name, f_in.name, filename))
+                        os.system(
+                            "patch -s -o %s %s %s" % (f_out.name, f_in.name, filename)
+                        )
 
                         # Store the updated snapshot and remove the temporary files
                         outputs[rname][step][file] = open(f_out.name).read()
                         f_in.close()
                         f_out.close()
 
+@pytest.mark.isis
 def setup_module(mod):
     "Sets up the pytest environment"
     tgen = Topogen(TemplateTopo, mod.__name__)
@@ -179,18 +186,17 @@ def setup_module(mod):
     router_list = tgen.routers()
 
     # For all registered routers, load the zebra configuration file
-    for rname, router in router_list.iteritems():
+    for rname, router in router_list.items():
         router.load_config(
-            TopoRouter.RD_ZEBRA,
-            os.path.join(CWD, '{}/zebra.conf'.format(rname))
+            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
         )
         router.load_config(
-            TopoRouter.RD_ISIS,
-            os.path.join(CWD, '{}/isisd.conf'.format(rname))
+            TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
         )
 
     tgen.start_router()
 
+
 def teardown_module(mod):
     "Teardown the pytest environment"
     tgen = get_topogen()
@@ -198,6 +204,7 @@ def teardown_module(mod):
     # This function tears down the whole topology.
     tgen.stop_topology()
 
+
 def router_compare_json_output(rname, command, reference):
     "Compare router JSON output"
 
@@ -207,12 +214,12 @@ def router_compare_json_output(rname, command, reference):
     expected = json.loads(reference)
 
     # Run test function until we get an result. Wait at most 60 seconds.
-    test_func = partial(topotest.router_json_cmp,
-        tgen.gears[rname], command, expected)
+    test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
     _, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
     assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
     assert diff is None, assertmsg
 
+
 #
 # Step 1
 #
@@ -226,9 +233,13 @@ def test_isis_adjacencies_step1():
     if tgen.routers_have_failure():
         pytest.skip(tgen.errors)
 
-    for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
-        router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd",
-                                   outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname,
+            "show yang operational-data /frr-interface:lib isisd",
+            outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"],
+        )
+
 
 def test_rib_ipv4_step1():
     logger.info("Test (step 1): verify IPv4 RIB")
@@ -238,9 +249,11 @@ def test_rib_ipv4_step1():
     if tgen.routers_have_failure():
         pytest.skip(tgen.errors)
 
-    for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
-        router_compare_json_output(rname, "show ip route isis json",
-                                   outputs[rname][1]["show_ip_route.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][1]["show_ip_route.ref"]
+        )
+
 
 def test_rib_ipv6_step1():
     logger.info("Test (step 1): verify IPv6 RIB")
@@ -250,9 +263,11 @@ def test_rib_ipv6_step1():
     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][1]["show_ipv6_route.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][1]["show_ipv6_route.ref"]
+        )
+
 
 def test_mpls_lib_step1():
     logger.info("Test (step 1): verify MPLS LIB")
@@ -262,9 +277,11 @@ def test_mpls_lib_step1():
     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][1]["show_mpls_table.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show mpls table json", outputs[rname][1]["show_mpls_table.ref"]
+        )
+
 
 #
 # Step 2
@@ -283,12 +300,16 @@ def test_rib_ipv4_step2():
     if tgen.routers_have_failure():
         pytest.skip(tgen.errors)
 
-    logger.info('Disabling TI-LFA link protection on rt2\'s eth-sw1 interface')
-    tgen.net['rt2'].cmd('vtysh -c "conf t" -c "interface eth-sw1" -c "no isis fast-reroute ti-lfa"')
+    logger.info("Disabling TI-LFA link protection on rt2's eth-sw1 interface")
+    tgen.net["rt2"].cmd(
+        'vtysh -c "conf t" -c "interface eth-sw1" -c "no isis fast-reroute ti-lfa"'
+    )
+
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][2]["show_ip_route.ref"]
+        )
 
-    for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
-        router_compare_json_output(rname, "show ip route isis json",
-                                   outputs[rname][2]["show_ip_route.ref"])
 
 def test_rib_ipv6_step2():
     logger.info("Test (step 2): verify IPv6 RIB")
@@ -298,9 +319,11 @@ def test_rib_ipv6_step2():
     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][2]["show_ipv6_route.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][2]["show_ipv6_route.ref"]
+        )
+
 
 def test_mpls_lib_step2():
     logger.info("Test (step 2): verify MPLS LIB")
@@ -310,9 +333,11 @@ def test_mpls_lib_step2():
     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][2]["show_mpls_table.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show mpls table json", outputs[rname][2]["show_mpls_table.ref"]
+        )
+
 
 #
 # Step 3
@@ -331,12 +356,16 @@ def test_rib_ipv4_step3():
     if tgen.routers_have_failure():
         pytest.skip(tgen.errors)
 
-    logger.info('Enabling TI-LFA link protection on rt2\'s eth-sw1 interface')
-    tgen.net['rt2'].cmd('vtysh -c "conf t" -c "interface eth-sw1" -c "isis fast-reroute ti-lfa"')
+    logger.info("Enabling TI-LFA link protection on rt2's eth-sw1 interface")
+    tgen.net["rt2"].cmd(
+        'vtysh -c "conf t" -c "interface eth-sw1" -c "isis fast-reroute ti-lfa"'
+    )
+
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][3]["show_ip_route.ref"]
+        )
 
-    for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
-        router_compare_json_output(rname, "show ip route isis json",
-                                   outputs[rname][3]["show_ip_route.ref"])
 
 def test_rib_ipv6_step3():
     logger.info("Test (step 3): verify IPv6 RIB")
@@ -346,9 +375,11 @@ def test_rib_ipv6_step3():
     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][3]["show_ipv6_route.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][3]["show_ipv6_route.ref"]
+        )
+
 
 def test_mpls_lib_step3():
     logger.info("Test (step 3): verify MPLS LIB")
@@ -358,9 +389,11 @@ def test_mpls_lib_step3():
     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][3]["show_mpls_table.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show mpls table json", outputs[rname][3]["show_mpls_table.ref"]
+        )
+
 
 #
 # Step 4
@@ -384,12 +417,16 @@ def test_rib_ipv4_step4():
     if tgen.routers_have_failure():
         pytest.skip(tgen.errors)
 
-    logger.info('Disabling SR on rt4')
-    tgen.net['rt4'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no segment-routing on"')
+    logger.info("Disabling SR on rt4")
+    tgen.net["rt4"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "no segment-routing on"'
+    )
+
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][4]["show_ip_route.ref"]
+        )
 
-    for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
-        router_compare_json_output(rname, "show ip route isis json",
-                                   outputs[rname][4]["show_ip_route.ref"])
 
 def test_rib_ipv6_step4():
     logger.info("Test (step 4): verify IPv6 RIB")
@@ -399,9 +436,11 @@ def test_rib_ipv6_step4():
     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][4]["show_ipv6_route.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][4]["show_ipv6_route.ref"]
+        )
+
 
 def test_mpls_lib_step4():
     logger.info("Test (step 4): verify MPLS LIB")
@@ -411,9 +450,11 @@ def test_mpls_lib_step4():
     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][4]["show_mpls_table.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show mpls table json", outputs[rname][4]["show_mpls_table.ref"]
+        )
+
 
 #
 # Step 5
@@ -432,12 +473,14 @@ def test_rib_ipv4_step5():
     if tgen.routers_have_failure():
         pytest.skip(tgen.errors)
 
-    logger.info('Enabling SR on rt4')
-    tgen.net['rt4'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing on"')
+    logger.info("Enabling SR on rt4")
+    tgen.net["rt4"].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing on"')
+
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][5]["show_ip_route.ref"]
+        )
 
-    for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
-        router_compare_json_output(rname, "show ip route isis json",
-                                   outputs[rname][5]["show_ip_route.ref"])
 
 def test_rib_ipv6_step5():
     logger.info("Test (step 5): verify IPv6 RIB")
@@ -447,9 +490,11 @@ def test_rib_ipv6_step5():
     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][5]["show_ipv6_route.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][5]["show_ipv6_route.ref"]
+        )
+
 
 def test_mpls_lib_step5():
     logger.info("Test (step 5): verify MPLS LIB")
@@ -459,9 +504,11 @@ def test_mpls_lib_step5():
     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][5]["show_mpls_table.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show mpls table json", outputs[rname][5]["show_mpls_table.ref"]
+        )
+
 
 #
 # Step 6
@@ -480,12 +527,16 @@ def test_rib_ipv4_step6():
     if tgen.routers_have_failure():
         pytest.skip(tgen.errors)
 
-    logger.info('Changing rt5\'s SRGB')
-    tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing global-block 30000 37999"')
+    logger.info("Changing rt5's SRGB")
+    tgen.net["rt5"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "segment-routing global-block 30000 37999"'
+    )
+
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][6]["show_ip_route.ref"]
+        )
 
-    for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
-        router_compare_json_output(rname, "show ip route isis json",
-                                   outputs[rname][6]["show_ip_route.ref"])
 
 def test_rib_ipv6_step6():
     logger.info("Test (step 6): verify IPv6 RIB")
@@ -495,9 +546,11 @@ def test_rib_ipv6_step6():
     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][6]["show_ipv6_route.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][6]["show_ipv6_route.ref"]
+        )
+
 
 def test_mpls_lib_step6():
     logger.info("Test (step 6): verify MPLS LIB")
@@ -507,9 +560,11 @@ def test_mpls_lib_step6():
     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][6]["show_mpls_table.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show mpls table json", outputs[rname][6]["show_mpls_table.ref"]
+        )
+
 
 #
 # Step 7
@@ -529,13 +584,19 @@ def test_rib_ipv4_step7():
     if tgen.routers_have_failure():
         pytest.skip(tgen.errors)
 
-    logger.info('Deleting rt5\'s Prefix-SIDs')
-    tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no segment-routing prefix 5.5.5.5/32 index 50"')
-    tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no segment-routing prefix 2001:db8:1000::5/128 index 51"')
+    logger.info("Deleting rt5's Prefix-SIDs")
+    tgen.net["rt5"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "no segment-routing prefix 5.5.5.5/32 index 50"'
+    )
+    tgen.net["rt5"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "no segment-routing prefix 2001:db8:1000::5/128 index 51"'
+    )
+
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][7]["show_ip_route.ref"]
+        )
 
-    for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
-        router_compare_json_output(rname, "show ip route isis json",
-                                   outputs[rname][7]["show_ip_route.ref"])
 
 def test_rib_ipv6_step7():
     logger.info("Test (step 7): verify IPv6 RIB")
@@ -545,9 +606,11 @@ def test_rib_ipv6_step7():
     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][7]["show_ipv6_route.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][7]["show_ipv6_route.ref"]
+        )
+
 
 def test_mpls_lib_step7():
     logger.info("Test (step 7): verify MPLS LIB")
@@ -557,9 +620,11 @@ def test_mpls_lib_step7():
     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][7]["show_mpls_table.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show mpls table json", outputs[rname][7]["show_mpls_table.ref"]
+        )
+
 
 #
 # Step 8
@@ -578,13 +643,19 @@ def test_rib_ipv4_step8():
     if tgen.routers_have_failure():
         pytest.skip(tgen.errors)
 
-    logger.info('Re-adding rt5\'s Prefix-SIDs')
-    tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 5.5.5.5/32 index 50"')
-    tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::5/128 index 51"')
+    logger.info("Re-adding rt5's Prefix-SIDs")
+    tgen.net["rt5"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 5.5.5.5/32 index 50"'
+    )
+    tgen.net["rt5"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::5/128 index 51"'
+    )
+
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][8]["show_ip_route.ref"]
+        )
 
-    for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
-        router_compare_json_output(rname, "show ip route isis json",
-                                   outputs[rname][8]["show_ip_route.ref"])
 
 def test_rib_ipv6_step8():
     logger.info("Test (step 8): verify IPv6 RIB")
@@ -594,9 +665,11 @@ def test_rib_ipv6_step8():
     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][8]["show_ipv6_route.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][8]["show_ipv6_route.ref"]
+        )
+
 
 def test_mpls_lib_step8():
     logger.info("Test (step 8): verify MPLS LIB")
@@ -606,9 +679,11 @@ def test_mpls_lib_step8():
     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][8]["show_mpls_table.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show mpls table json", outputs[rname][8]["show_mpls_table.ref"]
+        )
+
 
 #
 # Step 9
@@ -628,13 +703,19 @@ def test_rib_ipv4_step9():
     if tgen.routers_have_failure():
         pytest.skip(tgen.errors)
 
-    logger.info('Re-adding rt5\'s Prefix-SIDs')
-    tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 5.5.5.5/32 index 500"')
-    tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::5/128 index 501"')
+    logger.info("Re-adding rt5's Prefix-SIDs")
+    tgen.net["rt5"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 5.5.5.5/32 index 500"'
+    )
+    tgen.net["rt5"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::5/128 index 501"'
+    )
+
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][9]["show_ip_route.ref"]
+        )
 
-    for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
-        router_compare_json_output(rname, "show ip route isis json",
-                                   outputs[rname][9]["show_ip_route.ref"])
 
 def test_rib_ipv6_step9():
     logger.info("Test (step 9): verify IPv6 RIB")
@@ -644,9 +725,11 @@ def test_rib_ipv6_step9():
     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][9]["show_ipv6_route.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][9]["show_ipv6_route.ref"]
+        )
+
 
 def test_mpls_lib_step9():
     logger.info("Test (step 9): verify MPLS LIB")
@@ -656,19 +739,22 @@ def test_mpls_lib_step9():
     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][9]["show_mpls_table.ref"])
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+        router_compare_json_output(
+            rname, "show mpls table json", outputs[rname][9]["show_mpls_table.ref"]
+        )
+
 
 # Memory leak test template
 def test_memory_leak():
     "Run the memory leak test and report results."
     tgen = get_topogen()
     if not tgen.is_memleak_enabled():
-        pytest.skip('Memory leak test/report is disabled')
+        pytest.skip("Memory leak test/report is disabled")
 
     tgen.report_memory_leaks()
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     args = ["-s"] + sys.argv[1:]
     sys.exit(pytest.main(args))
index 12121e4ddf65cf3ff2df876cf489d7882c772b6b..a79c8a268b1e1872754a2e8b253ca572746e7394 100644 (file)
@@ -82,7 +82,7 @@ class ISISTopo1(Topo):
         sw.add_link(tgen.gears["r4"])
         sw.add_link(tgen.gears["r5"])
 
-
+@pytest.mark.isis
 def setup_module(mod):
     "Sets up the pytest environment"
     tgen = Topogen(ISISTopo1, mod.__name__)
index 71005a03623dcb1af017290d5d2e0f80bb4ee431..25116d94522569499d5f811e0fa57ad6efe5005d 100644 (file)
@@ -84,7 +84,7 @@ class ISISTopo1(Topo):
         sw.add_link(tgen.gears["r4"])
         sw.add_link(tgen.gears["r5"])
 
-
+@pytest.mark.isis
 def setup_module(mod):
     "Sets up the pytest environment"
     tgen = Topogen(ISISTopo1, mod.__name__)
index 87d5703d9e38c5e3a76ce804200094244cfa1fb7..877e14ff36d57291ec298499bab08f0f90a6b3e7 100644 (file)
@@ -8,4 +8,5 @@ router ospf
 int r1-eth0
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 1
 !
index 2c493173f51d1fa713acd9a1cdaa31e761808746..aa3f74fc5f12e96cee05f51aa12d192127c6bb6c 100644 (file)
@@ -2,7 +2,7 @@
   "neighbors":{
     "2.2.2.2":[
       {
-        "priority":1,
+        "priority":2,
         "state":"Full\/DR",
         "address":"10.0.1.2",
         "ifaceName":"r1-eth0:10.0.1.1"
index 51317202bb7bdcdc6050e48c2bfcd70a469db72d..8cba1529e8bee613585539b2d67e23484ffd767f 100644 (file)
@@ -8,8 +8,10 @@ router ospf
 int r2-eth0
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 2
 !
 int r2-eth1
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 1
 !
index 55f12359e51143adc3ed09e6966af2b7faf237f6..aa68198957b610ec89acfcd1ec9df63c5b3d692a 100644 (file)
@@ -5,15 +5,12 @@
         "priority":1,
         "state":"Full\/Backup",
         "address":"10.0.1.1",
-        "ifaceName":"r2-eth0:10.0.1.2",
-        "retransmitCounter":0,
-        "requestCounter":0,
-        "dbSummaryCounter":0
+        "ifaceName":"r2-eth0:10.0.1.2"
       }
     ],
     "3.3.3.3":[
       {
-        "priority":1,
+        "priority":2,
         "state":"Full\/Backup",
         "address":"10.0.2.3",
         "ifaceName":"r2-eth1:10.0.2.2"
@@ -21,7 +18,7 @@
     ],
     "4.4.4.4":[
       {
-        "priority":1,
+        "priority":3,
         "state":"Full\/DR",
         "address":"10.0.2.4",
         "ifaceName":"r2-eth1:10.0.2.2"
index 4566976b7b315826abcd5dab722bc0184966057a..0d3a74c4ac260af94914ad8ca5a8171091832bf8 100644 (file)
@@ -9,4 +9,5 @@ router ospf
 int r3-eth0
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 2
 !
index 24502ed81334bad729af77186268915c59b89e09..905774fc466ad5ae6637077561a54a379f99a422 100644 (file)
@@ -10,7 +10,7 @@
     ],
     "4.4.4.4":[
       {
-        "priority":1,
+        "priority":3,
         "state":"Full\/DR",
         "address":"10.0.2.4",
         "ifaceName":"r3-eth0:10.0.2.3"
index 5aae885a1248fd88578755d46535bdf5c4e64de5..7bbd228d024b61d62c2e79b7bc18f11086c2eb48 100644 (file)
@@ -8,4 +8,5 @@ router ospf
 int r4-eth0
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 3
 !
index 794410522dfb9cd55d1a63c14df3aa03702ff5b5..67593952cae13d737e0c3944f4b185029501f223 100644 (file)
@@ -11,7 +11,7 @@
     ],
     "3.3.3.3":[
       {
-        "priority":1,
+        "priority":2,
         "state":"Full\/Backup",
         "address":"10.0.2.3",
         "ifaceName":"r4-eth0:10.0.2.4"
index 87d5703d9e38c5e3a76ce804200094244cfa1fb7..877e14ff36d57291ec298499bab08f0f90a6b3e7 100644 (file)
@@ -8,4 +8,5 @@ router ospf
 int r1-eth0
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 1
 !
index 2c493173f51d1fa713acd9a1cdaa31e761808746..aa3f74fc5f12e96cee05f51aa12d192127c6bb6c 100644 (file)
@@ -2,7 +2,7 @@
   "neighbors":{
     "2.2.2.2":[
       {
-        "priority":1,
+        "priority":2,
         "state":"Full\/DR",
         "address":"10.0.1.2",
         "ifaceName":"r1-eth0:10.0.1.1"
index 51317202bb7bdcdc6050e48c2bfcd70a469db72d..8cba1529e8bee613585539b2d67e23484ffd767f 100644 (file)
@@ -8,8 +8,10 @@ router ospf
 int r2-eth0
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 2
 !
 int r2-eth1
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 1
 !
index 55f12359e51143adc3ed09e6966af2b7faf237f6..aa68198957b610ec89acfcd1ec9df63c5b3d692a 100644 (file)
@@ -5,15 +5,12 @@
         "priority":1,
         "state":"Full\/Backup",
         "address":"10.0.1.1",
-        "ifaceName":"r2-eth0:10.0.1.2",
-        "retransmitCounter":0,
-        "requestCounter":0,
-        "dbSummaryCounter":0
+        "ifaceName":"r2-eth0:10.0.1.2"
       }
     ],
     "3.3.3.3":[
       {
-        "priority":1,
+        "priority":2,
         "state":"Full\/Backup",
         "address":"10.0.2.3",
         "ifaceName":"r2-eth1:10.0.2.2"
@@ -21,7 +18,7 @@
     ],
     "4.4.4.4":[
       {
-        "priority":1,
+        "priority":3,
         "state":"Full\/DR",
         "address":"10.0.2.4",
         "ifaceName":"r2-eth1:10.0.2.2"
index 4566976b7b315826abcd5dab722bc0184966057a..0d3a74c4ac260af94914ad8ca5a8171091832bf8 100644 (file)
@@ -9,4 +9,5 @@ router ospf
 int r3-eth0
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 2
 !
index 24502ed81334bad729af77186268915c59b89e09..905774fc466ad5ae6637077561a54a379f99a422 100644 (file)
@@ -10,7 +10,7 @@
     ],
     "4.4.4.4":[
       {
-        "priority":1,
+        "priority":3,
         "state":"Full\/DR",
         "address":"10.0.2.4",
         "ifaceName":"r3-eth0:10.0.2.3"
index 5aae885a1248fd88578755d46535bdf5c4e64de5..7bbd228d024b61d62c2e79b7bc18f11086c2eb48 100644 (file)
@@ -8,4 +8,5 @@ router ospf
 int r4-eth0
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 3
 !
index 794410522dfb9cd55d1a63c14df3aa03702ff5b5..67593952cae13d737e0c3944f4b185029501f223 100644 (file)
@@ -11,7 +11,7 @@
     ],
     "3.3.3.3":[
       {
-        "priority":1,
+        "priority":2,
         "state":"Full\/Backup",
         "address":"10.0.2.3",
         "ifaceName":"r4-eth0:10.0.2.4"
index 31adeafbf67cc2b1e486769bee048592a632ca05..dfe65f010e5e2f8f8a88bd09226da561ffe4a342 100644 (file)
@@ -159,7 +159,7 @@ class NetworkTopo(Topo):
 ##
 #####################################################
 
-
+@pytest.mark.ldp
 def setup_module(module):
     global topo, net
     global fatal_error
@@ -647,9 +647,11 @@ def test_zebra_ipv4_routingTable():
             else:
                 print("r%s ok" % i)
 
-            assert failures == 0, (
-                "IPv4 Zebra Routing Table verification failed for router r%s:\n%s"
-                % (i, diff)
+            assert (
+                failures == 0
+            ), "IPv4 Zebra Routing Table verification failed for router r%s:\n%s" % (
+                i,
+                diff,
             )
 
     # Make sure that all daemons are running
index 76ea32fb61285a15711d38862df634fb22c4f2bb..a66fb92ba3753b4b83c1ccd255ee9117644254ff 100644 (file)
@@ -8,8 +8,10 @@ router ospf
 int r1-eth1
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 1
 !
 int r1-eth2
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 1
 !
index 6e6c3c8cb805422686f38faded1e903717bab0e5..7e281abb5fd43128ea29e8879a7a84010669479f 100644 (file)
@@ -4,8 +4,8 @@
       {
         "dbSummaryCounter": 0,
         "retransmitCounter": 0,
-        "priority": 1,
-        "state": "Full/DR",
+        "priority": 2,
+        "state": "Full\/DR",
         "address": "10.0.1.2",
         "ifaceName": "r1-eth1:10.0.1.1",
         "requestCounter": 0
@@ -15,8 +15,8 @@
       {
         "dbSummaryCounter": 0,
         "retransmitCounter": 0,
-        "priority": 1,
-        "state": "Full/DR",
+        "priority": 2,
+        "state": "Full\/DR",
         "address": "10.0.2.3",
         "ifaceName": "r1-eth2:10.0.2.1",
         "requestCounter": 0
index 7b3ddfe371bef394542696cdd2c8f41908eabd47..b4692feec857841f7a8f07c2972b84336fe21b75 100644 (file)
@@ -8,8 +8,10 @@ router ospf
 int r2-eth1
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 2
 !
 int r2-eth2
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 1
 !
index b5b10cc5350f4214432c115793a4045adf7d6fd4..22fd98f519c38d703ffe05f91de859a8eec88aaf 100644 (file)
@@ -3,7 +3,7 @@
     "1.1.1.1": [
       {
         "priority":1,
-        "state":"Full/Backup",
+        "state":"Full\/Backup",
         "address":"10.0.1.1",
         "ifaceName":"r2-eth1:10.0.1.2",
         "retransmitCounter":0,
@@ -13,8 +13,8 @@
     ],
     "3.3.3.3": [
       {
-        "priority":1,
-        "state":"Full/DR",
+        "priority":2,
+        "state":"Full\/DR",
         "address":"10.0.3.3",
         "ifaceName":"r2-eth2:10.0.3.2",
         "retransmitCounter":0,
index b424f2e1086af5ceca734df56b0340d1d90aa601..2413bfa9d5be912ba02c5d7265ebbb68d5b54908 100644 (file)
@@ -8,8 +8,10 @@ router ospf
 int r3-eth1
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 2
 !
 int r3-eth2
  ip ospf hello-interval 2
  ip ospf dead-interval 10
+ ip ospf priority 2
 !
index bc7bb1e8944431fe0e7183911a62a6840931cf6c..970eb2fc1d72f7a640bcef535e595564ce711d19 100644 (file)
@@ -3,7 +3,7 @@
     "1.1.1.1": [
       {
         "priority":1,
-        "state":"Full/Backup",
+        "state":"Full\/Backup",
         "address":"10.0.2.1",
         "ifaceName":"r3-eth1:10.0.2.3",
         "retransmitCounter":0,
@@ -14,7 +14,7 @@
     "2.2.2.2": [
       {
         "priority":1,
-        "state":"Full/Backup",
+        "state":"Full\/Backup",
         "address":"10.0.3.2",
         "ifaceName":"r3-eth2:10.0.3.3",
         "retransmitCounter":0,
index dd7c6f74d05f98c9437e8ef15d431ca57bdbd3a6..4d26732ea7c54efdb47023e8a056fb7d1a8cbf20 100644 (file)
Binary files a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.pdf and b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.pdf differ
index ba94cd47d4b20c7638852c10bce27d66d89cde9b..d659acb470866421f8c762eaf79aec492f144646 100644 (file)
@@ -121,7 +121,8 @@ class TemplateTopo(Topo):
         switch.add_link(tgen.gears["r2"])
         switch.add_link(tgen.gears["r3"])
 
-
+@pytest.mark.ldp
+@pytest.mark.ospf
 def setup_module(mod):
     "Sets up the pytest environment"
     tgen = Topogen(TemplateTopo, mod.__name__)
index 8427b241b76873b5dff66770f9d8389352015e3f..22602cb460693b239e1b76f4a7862a9ce54003dd 100644 (file)
@@ -21,6 +21,7 @@
 from copy import deepcopy
 from time import sleep
 import traceback
+import ipaddr
 import ipaddress
 import os
 import sys
@@ -691,8 +692,8 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
                 config_data.append("{} activate".format(neigh_cxt))
 
             disable_connected = peer.setdefault("disable_connected_check", False)
-            keep_alive = peer.setdefault("keepalivetimer", 60)
-            hold_down = peer.setdefault("holddowntimer", 180)
+            keep_alive = peer.setdefault("keepalivetimer", 3)
+            hold_down = peer.setdefault("holddowntimer", 10)
             password = peer.setdefault("password", None)
             no_password = peer.setdefault("no_password", None)
             max_hop_limit = peer.setdefault("ebgp_multihop", 1)
@@ -1615,8 +1616,6 @@ def clear_bgp(tgen, addr_type, router, vrf=None):
     else:
         run_frr_cmd(rnode, "clear bgp *")
 
-    sleep(5)
-
     logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
 
 
@@ -2115,8 +2114,8 @@ def verify_bgp_attributes(
     errormsg(str) or True
     """
 
-    logger.debug("Entering lib API: verify_bgp_attributes()")
-    for router, rnode in tgen.routers().items():
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+    for router, rnode in tgen.routers().iteritems():
         if router != dut:
             continue
 
@@ -2129,7 +2128,9 @@ def verify_bgp_attributes(
             dict_to_test = []
             tmp_list = []
 
-            if "route_maps" in input_dict.values()[0]:
+            dict_list = list(input_dict.values())[0]
+
+            if "route_maps" in dict_list:
                 for rmap_router in input_dict.keys():
                     for rmap, values in input_dict[rmap_router]["route_maps"].items():
                         if rmap == rmap_name:
@@ -2194,7 +2195,7 @@ def verify_bgp_attributes(
                                             )
                                             return errormsg
 
-    logger.debug("Exiting lib API: verify_bgp_attributes()")
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
     return True
 
 
@@ -2514,8 +2515,9 @@ def verify_best_path_as_per_admin_distance(
     return True
 
 
-@retry(attempts=6, wait=2, return_is_str=True)
-def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None):
+@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
+def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None,
+aspath=None, multi_nh=None):
     """
     This API is to verify whether bgp rib has any
     matching route for a nexthop.
@@ -2550,6 +2552,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
     additional_nexthops_in_required_nhs = []
     list1 = []
     list2 = []
+    found_hops = []
     for routerInput in input_dict.keys():
         for router, rnode in router_list.items():
             if router != dut:
@@ -2616,44 +2619,73 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
                             st_found = True
                             found_routes.append(st_rt)
 
-                            if next_hop:
+                            if next_hop and multi_nh and st_found:
                                 if not isinstance(next_hop, list):
                                     next_hop = [next_hop]
                                     list1 = next_hop
 
-                                found_hops = [
-                                    rib_r["ip"]
-                                    for rib_r in rib_routes_json["routes"][st_rt][0][
-                                        "nexthops"
-                                    ]
-                                ]
-                                list2 = found_hops
-
-                                missing_list_of_nexthops = set(list2).difference(list1)
-                                additional_nexthops_in_required_nhs = set(
-                                    list1
-                                ).difference(list2)
+                                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 found_hops:
+                                    for each_nh_in_multipath in mnh:
+                                        list2.append(each_nh_in_multipath)
+                                if found_hops[0]:
+                                    missing_list_of_nexthops = set(list2).difference(
+                                        list1
+                                    )
+                                    additional_nexthops_in_required_nhs = set(
+                                        list1
+                                    ).difference(list2)
 
-                                if list2:
-                                    if additional_nexthops_in_required_nhs:
-                                        logger.info(
-                                            "Missing nexthop %s for route"
-                                            " %s in RIB of router %s\n",
-                                            additional_nexthops_in_required_nhs,
-                                            st_rt,
-                                            dut,
-                                        )
-                                        errormsg = (
-                                            "Nexthop {} is Missing for "
-                                            "route {} in RIB of router {}\n".format(
+                                    if list2:
+                                        if additional_nexthops_in_required_nhs:
+                                            logger.info(
+                                                "Missing nexthop %s for route"
+                                                " %s in RIB of router %s\n",
                                                 additional_nexthops_in_required_nhs,
                                                 st_rt,
                                                 dut,
                                             )
-                                        )
                                         return errormsg
                                     else:
                                         nh_found = True
+
+                            elif next_hop and multi_nh is None:
+                                if not isinstance(next_hop, list):
+                                    next_hop = [next_hop]
+                                    list1 = next_hop
+                                found_hops = [rib_r["ip"] for rib_r in
+                                              rib_routes_json["routes"][
+                                                  st_rt][0]["nexthops"]]
+                                list2 = found_hops
+                                missing_list_of_nexthops = \
+                                    set(list2).difference(list1)
+                                additional_nexthops_in_required_nhs = \
+                                    set(list1).difference(list2)
+
+                                if list2:
+                                    if additional_nexthops_in_required_nhs:
+                                        logger.info("Missing nexthop %s for route"\
+                                        " %s in RIB of router %s\n", \
+                                        additional_nexthops_in_required_nhs,  \
+                                        st_rt, dut)
+                                        errormsg=("Nexthop {} is Missing for "\
+                                        "route {} in RIB of router {}\n".format(
+                                            additional_nexthops_in_required_nhs,
+                                            st_rt, dut))
+                                        return errormsg
+                                    else:
+                                        nh_found = True
+
                             if aspath:
                                 found_paths = rib_routes_json["routes"][st_rt][0][
                                     "path"
@@ -3676,7 +3708,6 @@ def verify_attributes_for_evpn_routes(
     """
     API to verify rd and rt value using "sh bgp l2vpn evpn 10.1.1.1"
     command.
-
     Parameters
     ----------
     * `tgen`: topogen object
@@ -3690,7 +3721,6 @@ def verify_attributes_for_evpn_routes(
     * `ipLen` : IP prefix length
     * `rd_peer` : Peer name from which RD will be auto-generated
     * `rt_peer` : Peer name from which RT will be auto-generated
-
     Usage
     -----
         input_dict_1 = {
@@ -3762,7 +3792,7 @@ def verify_attributes_for_evpn_routes(
                                 logger.info(
                                     "[DUT %s]: Verifying RD value for"
                                     " EVPN route: %s [PASSED]|| "
-                                    "Found Exprected: %s",
+                                    "Found Expected: %s",
                                     dut,
                                     route,
                                     rd,
@@ -3808,34 +3838,33 @@ def verify_attributes_for_evpn_routes(
                                 continue
                             router_id = afi_data["routerId"]
 
+                        found = False
                         rd = "{}:{}".format(router_id, vni_dict[vrf])
-                        if rd in evpn_rd_value_json:
-                            rd_value_json = evpn_rd_value_json[rd]
-                            if rd_value_json["rd"] != rd:
-                                errormsg = (
-                                    "[DUT: %s] Failed: Verifying"
-                                    " RD value for EVPN route: %s"
-                                    "[FAILED]!!, EXPECTED  : %s "
-                                    " FOUND : %s"
-                                    % (dut, route, rd, rd_value_json["rd"])
-                                )
-                                return errormsg
+                        for _rd, rd_value_json in evpn_rd_value_json.items():
+                            if (
+                                str(rd_value_json["rd"].split(":")[0])
+                                != rd.split(":")[0]
+                            ):
+                                continue
 
-                            else:
-                                logger.info(
-                                    "[DUT %s]: Verifying RD value for"
-                                    " EVPN route: %s [PASSED]|| "
-                                    "Found Exprected: %s",
-                                    dut,
-                                    route,
-                                    rd,
-                                )
-                                return True
+                            if int(rd_value_json["rd"].split(":")[1]) > 0:
+                                found = True
 
+                        if found:
+                            logger.info(
+                                "[DUT %s]: Verifying RD value for"
+                                " EVPN route: %s "
+                                "Found Expected: %s",
+                                dut,
+                                route,
+                                rd_value_json["rd"],
+                            )
+                            return True
                         else:
                             errormsg = (
-                                "[DUT: %s] RD : %s is not present"
-                                " in cli json output" % (dut, rd)
+                                "[DUT: %s] Failed: Verifying"
+                                " RD value for EVPN route: %s"
+                                " FOUND : %s" % (dut, route, rd_value_json["rd"])
                             )
                             return errormsg
 
@@ -3908,7 +3937,7 @@ def verify_attributes_for_evpn_routes(
                                                 "[DUT %s]: Verifying "
                                                 "RT value for EVPN "
                                                 "route: %s [PASSED]||"
-                                                "Found Exprected: %s",
+                                                "Found Expected: %s",
                                                 dut,
                                                 route,
                                                 rt_input,
@@ -3957,7 +3986,7 @@ def verify_attributes_for_evpn_routes(
                                                 "[DUT %s]: Verifying RT"
                                                 " value for EVPN route:"
                                                 " %s [PASSED]|| "
-                                                "Found Exprected: %s",
+                                                "Found Expected: %s",
                                                 dut,
                                                 route,
                                                 rt_input,
@@ -4001,7 +4030,7 @@ def verify_attributes_for_evpn_routes(
                                         "[DUT %s]: RD: %s, Verifying "
                                         "ethTag value for EVPN route:"
                                         " %s [PASSED]|| "
-                                        "Found Exprected: %s",
+                                        "Found Expected: %s",
                                         dut,
                                         _rd,
                                         route,
@@ -4041,7 +4070,7 @@ def verify_attributes_for_evpn_routes(
                                         "[DUT %s]: RD: %s, Verifying "
                                         "ipLen value for EVPN route:"
                                         " %s [PASSED]|| "
-                                        "Found Exprected: %s",
+                                        "Found Expected: %s",
                                         dut,
                                         _rd,
                                         route,
@@ -4068,7 +4097,6 @@ def verify_evpn_routes(
     """
     API to verify evpn routes using "sh bgp l2vpn evpn"
     command.
-
     Parameters
     ----------
     * `tgen`: topogen object
@@ -4079,7 +4107,6 @@ def verify_evpn_routes(
     * `route_type` : Route type 5 is supported as of now
     * `EthTag` : Ethernet tag, by-default is 0
     * `next_hop` : Prefered nexthop for the evpn routes
-
     Usage
     -----
         input_dict_1 = {
@@ -4092,7 +4119,6 @@ def verify_evpn_routes(
             }
         }
         result = verify_evpn_routes(tgen, topo, input_dict)
-
     Returns
     -------
     errormsg(str) or True
index a23092de832b58c34aec6758bbbb2fc53f97a554..abab9600a1d8e0c970cd153e03255b95572a1288 100644 (file)
@@ -45,7 +45,7 @@ class BgpRib:
 
     def routes_include_wanted(self, pfxtbl, want, debug):
         # helper function to RequireVpnRoutes
-        for pfx in pfxtbl.iterkeys():
+        for pfx in pfxtbl.keys():
             if debug:
                 self.log("trying pfx %s" % pfx)
             if pfx != want["p"]:
@@ -107,7 +107,7 @@ class BgpRib:
             found = 0
             if debug:
                 self.log("want rd %s" % want["rd"])
-            for rd in rds.iterkeys():
+            for rd in rds.keys():
                 if rd != want["rd"]:
                     continue
                 if debug:
index 9c104db3cd70f1113d484f5d5399b7d624754990..175d660d1e1a990ca0c541165e5899604295caae 100644 (file)
@@ -31,7 +31,6 @@ from re import search as re_search
 from tempfile import mkdtemp
 
 import os
-import io
 import sys
 import traceback
 import socket
@@ -39,6 +38,7 @@ import ipaddress
 import platform
 
 if sys.version_info[0] > 2:
+    import io
     import configparser
 else:
     import StringIO
@@ -151,8 +151,8 @@ class InvalidCLIError(Exception):
 
 def run_frr_cmd(rnode, cmd, isjson=False):
     """
-    Execute frr show commands in priviledged mode
-    * `rnode`: router node on which commands needs to executed
+    Execute frr show commands in privileged mode
+    * `rnode`: router node on which command needs to be executed
     * `cmd`: Command to be executed on frr
     * `isjson`: If command is to get json data or not
     :return str:
@@ -184,11 +184,11 @@ def apply_raw_config(tgen, input_dict):
 
     """
     API to configure raw configuration on device. This can be used for any cli
-    which does has not been implemented in JSON.
+    which has not been implemented in JSON.
 
     Parameters
     ----------
-    * `tgen`: tgen onject
+    * `tgen`: tgen object
     * `input_dict`: configuration that needs to be applied
 
     Usage
@@ -232,8 +232,8 @@ def create_common_configuration(
     frr_json.conf and load to router
     Parameters
     ----------
-    * `tgen`: tgen onject
-    * `data`: Congiguration data saved in a list.
+    * `tgen`: tgen object
+    * `data`: Configuration data saved in a list.
     * `router` : router id to be configured.
     * `config_type` : Syntactic information while writing configuration. Should
                       be one of the value as mentioned in the config_map below.
@@ -257,6 +257,7 @@ def create_common_configuration(
             "bgp": "! BGP Config\n",
             "vrf": "! VRF Config\n",
             "ospf": "! OSPF Config\n",
+            "pim": "! PIM Config\n",
         }
     )
 
@@ -292,8 +293,8 @@ def create_common_configuration(
 
 def kill_router_daemons(tgen, router, daemons):
     """
-    Router's current config would be saved to /etc/frr/ for each deamon
-    and deamon would be killed forcefully using SIGKILL.
+    Router's current config would be saved to /etc/frr/ for each daemon
+    and daemon would be killed forcefully using SIGKILL.
     * `tgen`  : topogen object
     * `router`: Device under test
     * `daemons`: list of daemons to be killed
@@ -389,6 +390,8 @@ def check_router_status(tgen):
                     daemons.append("bgpd")
                 if "zebra" in result:
                     daemons.append("zebra")
+                if "pimd" in result:
+                    daemons.append("pimd")
 
                 rnode.startDaemons(daemons)
 
@@ -593,13 +596,13 @@ def load_config_to_router(tgen, routerName, save_bkup=False):
 
 def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None):
     """
-    API to get the link local ipv6 address of a perticular interface using
+    API to get the link local ipv6 address of a particular interface using
     FRR command 'show interface'
 
-    * `tgen`: tgen onject
-    * `router` : router for which hightest interface should be
+    * `tgen`: tgen object
+    * `router` : router for which highest interface should be
                  calculated
-    * `intf` : interface for which linklocal address needs to be taken
+    * `intf` : interface for which link-local address needs to be taken
     * `vrf` : VRF name
 
     Usage
@@ -688,7 +691,7 @@ def generate_support_bundle():
 def start_topology(tgen, daemon=None):
     """
     Starting topology, create tmp files which are loaded to routers
-    to start deamons and then start routers
+    to start daemons and then start routers
     * `tgen`  : topogen object
     """
 
@@ -696,7 +699,7 @@ def start_topology(tgen, daemon=None):
     # Starting topology
     tgen.start_topology()
 
-    # Starting deamons
+    # Starting daemons
 
     router_list = tgen.routers()
     ROUTER_LIST = sorted(
@@ -735,28 +738,35 @@ def start_topology(tgen, daemon=None):
         except IOError as err:
             logger.error("I/O error({0}): {1}".format(err.errno, err.strerror))
 
-        # Loading empty zebra.conf file to router, to start the zebra deamon
+        # Loading empty zebra.conf file to router, to start the zebra daemon
         router.load_config(
             TopoRouter.RD_ZEBRA, "{}/{}/zebra.conf".format(TMPDIR, rname)
         )
 
-        # Loading empty bgpd.conf file to router, to start the bgp deamon
+        # Loading empty bgpd.conf file to router, to start the bgp daemon
         router.load_config(TopoRouter.RD_BGP, "{}/{}/bgpd.conf".format(TMPDIR, rname))
 
         if daemon and "ospfd" in daemon:
-            # Loading empty ospf.conf file to router, to start the bgp deamon
+            # Loading empty ospf.conf file to router, to start the bgp daemon
             router.load_config(
                 TopoRouter.RD_OSPF, "{}/{}/ospfd.conf".format(TMPDIR, rname)
             )
-        # Starting routers
+
+        if daemon and "pimd" in daemon:
+            # Loading empty pimd.conf file to router, to start the pim deamon
+            router.load_config(
+                TopoRouter.RD_PIM, "{}/{}/pimd.conf".format(TMPDIR, rname)
+            )
+
+    # Starting routers
     logger.info("Starting all routers once topology is created")
     tgen.start_router()
 
 
 def stop_router(tgen, router):
     """
-    Router"s current config would be saved to /etc/frr/ for each deamon
-    and router and its deamons would be stopped.
+    Router"s current config would be saved to /tmp/topotest/<suite>/<router> for each daemon
+    and router and its daemons would be stopped.
 
     * `tgen`  : topogen object
     * `router`: Device under test
@@ -774,8 +784,8 @@ def stop_router(tgen, router):
 
 def start_router(tgen, router):
     """
-    Router will started and config would be loaded from /etc/frr/ for each
-    deamon
+    Router will be started and config would be loaded from /tmp/topotest/<suite>/<router> for each
+    daemon
 
     * `tgen`  : topogen object
     * `router`: Device under test
@@ -786,8 +796,8 @@ def start_router(tgen, router):
     try:
         router_list = tgen.routers()
 
-        # Router and its deamons would be started and config would
-        #  be loaded to router for each deamon from /etc/frr
+        # Router and its daemons would be started and config would
+        #  be loaded to router for each daemon from /etc/frr
         router_list[router].start()
 
         # Waiting for router to come up
@@ -835,9 +845,201 @@ def topo_daemons(tgen, topo):
         if "ospf" in topo["routers"][rtr] and "ospfd" not in daemon_list:
             daemon_list.append("ospfd")
 
+        for val in topo["routers"][rtr]["links"].values():
+            if "pim" in val and "pimd" not in daemon_list:
+                daemon_list.append("pimd")
+                break
+
     return daemon_list
 
 
+def add_interfaces_to_vlan(tgen, input_dict):
+    """
+    Add interfaces to VLAN, we need vlan pakcage to be installed on machine
+
+    * `tgen`: tgen onject
+    * `input_dict` : interfaces to be added to vlans
+
+    input_dict= {
+        "r1":{
+            "vlan":{
+                VLAN_1: [{
+                    intf_r1_s1: {
+                        "ip": "10.1.1.1",
+                        "subnet": "255.255.255.0
+                    }
+                }]
+            }
+        }
+    }
+
+    add_interfaces_to_vlan(tgen, input_dict)
+
+    """
+
+    router_list = tgen.routers()
+    for dut in input_dict.keys():
+        rnode = tgen.routers()[dut]
+
+        if "vlan" in input_dict[dut]:
+            for vlan, interfaces in input_dict[dut]["vlan"].items():
+                for intf_dict in interfaces:
+                    for interface, data in intf_dict.items():
+                        # Adding interface to VLAN
+                        cmd = "vconfig add {} {}".format(interface, vlan)
+                        logger.info("[DUT: %s]: Running command: %s", dut, cmd)
+                        rnode.run(cmd)
+
+                        vlan_intf = "{}.{}".format(interface, vlan)
+
+                        ip = data["ip"]
+                        subnet = data["subnet"]
+
+                        # Bringing interface up
+                        cmd = "ip link set up {}".format(vlan_intf)
+                        logger.info("[DUT: %s]: Running command: %s", dut, cmd)
+                        rnode.run(cmd)
+
+                        # Assigning IP address
+                        cmd = "ifconfig {} {} netmask {}".format(vlan_intf, ip, subnet)
+                        logger.info("[DUT: %s]: Running command: %s", dut, cmd)
+                        rnode.run(cmd)
+
+
+def tcpdump_capture_start(
+    tgen,
+    router,
+    intf,
+    protocol=None,
+    grepstr=None,
+    timeout=0,
+    options=None,
+    cap_file=None,
+    background=True,
+):
+    """
+    API to capture network packets using tcp dump.
+
+    Packages used :
+
+    Parameters
+    ----------
+    * `tgen`: topogen object.
+    * `router`: router on which ping has to be performed.
+    * `intf` : interface for capture.
+    * `protocol` : protocol for which packet needs to be captured.
+    * `grepstr` : string to filter out tcp dump output.
+    * `timeout` : Time for which packet needs to be captured.
+    * `options` : options for TCP dump, all tcpdump options can be used.
+    * `cap_file` : filename to store capture dump.
+    * `background` : Make tcp dump run in back ground.
+
+    Usage
+    -----
+    tcpdump_result = tcpdump_dut(tgen, 'r2', intf, protocol='tcp', timeout=20,
+        options='-A -vv -x  > r2bgp.txt ')
+    Returns
+    -------
+    1) True for successful capture
+    2) errormsg - when tcp dump fails
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    rnode = tgen.routers()[router]
+
+    if timeout > 0:
+        cmd = "timeout {}".format(timeout)
+    else:
+        cmd = ""
+
+    cmdargs = "{} tcpdump".format(cmd)
+
+    if intf:
+        cmdargs += " -i {}".format(str(intf))
+    if protocol:
+        cmdargs += " {}".format(str(protocol))
+    if options:
+        cmdargs += " -s 0 {}".format(str(options))
+
+    if cap_file:
+        file_name = os.path.join(LOGDIR, tgen.modname, router, cap_file)
+        cmdargs += " -w {}".format(str(file_name))
+        # Remove existing capture file
+        rnode.run("rm -rf {}".format(file_name))
+
+    if grepstr:
+        cmdargs += ' | grep "{}"'.format(str(grepstr))
+
+    logger.info("Running tcpdump command: [%s]", cmdargs)
+    if not background:
+        rnode.run(cmdargs)
+    else:
+        rnode.run("nohup {} & /dev/null 2>&1".format(cmdargs))
+
+    # Check if tcpdump process is running
+    if background:
+        result = rnode.run("pgrep tcpdump")
+        logger.debug("ps -ef | grep tcpdump \n {}".format(result))
+
+        if not result:
+            errormsg = "tcpdump is not running {}".format("tcpdump")
+            return errormsg
+        else:
+            logger.info("Packet capture started on %s: interface %s", router, intf)
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True
+
+
+def tcpdump_capture_stop(tgen, router):
+    """
+    API to capture network packets using tcp dump.
+
+    Packages used :
+
+    Parameters
+    ----------
+    * `tgen`: topogen object.
+    * `router`: router on which ping has to be performed.
+    * `intf` : interface for capture.
+    * `protocol` : protocol for which packet needs to be captured.
+    * `grepstr` : string to filter out tcp dump output.
+    * `timeout` : Time for which packet needs to be captured.
+    * `options` : options for TCP dump, all tcpdump options can be used.
+    * `cap2file` : filename to store capture dump.
+    * `bakgrnd` : Make tcp dump run in back ground.
+
+    Usage
+    -----
+    tcpdump_result = tcpdump_dut(tgen, 'r2', intf, protocol='tcp', timeout=20,
+        options='-A -vv -x  > r2bgp.txt ')
+    Returns
+    -------
+    1) True for successful capture
+    2) errormsg - when tcp dump fails
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    rnode = tgen.routers()[router]
+
+    # Check if tcpdump process is running
+    result = rnode.run("ps -ef | grep tcpdump")
+    logger.debug("ps -ef | grep tcpdump \n {}".format(result))
+
+    if not re_search(r"{}".format("tcpdump"), result):
+        errormsg = "tcpdump is not running {}".format("tcpdump")
+        return errormsg
+    else:
+        ppid = tgen.net.nameToNode[rnode.name].pid
+        rnode.run("set +m; pkill -P %s tcpdump &> /dev/null" % ppid)
+        logger.info("Stopped tcpdump capture")
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True
+
+
 #############################################
 # Common APIs, will be used by all protocols
 #############################################
@@ -1137,11 +1339,11 @@ def generate_ips(network, no_of_ips):
     """
     Returns list of IPs.
     based on start_ip and no_of_ips
+
     * `network`  : from here the ip will start generating,
                    start_ip will be
     * `no_of_ips` : these many IPs will be generated
     """
-
     ipaddress_list = []
     if type(network) is not list:
         network = [network]
@@ -1150,13 +1352,22 @@ def generate_ips(network, no_of_ips):
         if "/" in start_ipaddr:
             start_ip = start_ipaddr.split("/")[0]
             mask = int(start_ipaddr.split("/")[1])
+        else:
+            logger.debug("start_ipaddr {} must have a / in it".format(start_ipaddr))
+            assert 0
 
         addr_type = validate_ip_address(start_ip)
         if addr_type == "ipv4":
-            start_ip = ipaddress.IPv4Address(frr_unicode(start_ip))
+            if start_ip == "0.0.0.0" and mask == 0 and no_of_ips == 1:
+                ipaddress_list.append("{}/{}".format(start_ip, mask))
+                return ipaddress_list
+            start_ip = ipaddress.IPv4Address(unicode(start_ip))
             step = 2 ** (32 - mask)
         if addr_type == "ipv6":
-            start_ip = ipaddress.IPv6Address(frr_unicode(start_ip))
+            if start_ip == "0::0" and mask == 0 and no_of_ips == 1:
+                ipaddress_list.append("{}/{}".format(start_ip, mask))
+                return ipaddress_list
+            start_ip = ipaddress.IPv6Address(unicode(start_ip))
             step = 2 ** (128 - mask)
 
         next_ip = start_ip
@@ -1178,7 +1389,7 @@ def find_interface_with_greater_ip(topo, router, loopback=True, interface=True):
     it will return highest IP from loopback IPs otherwise from physical
     interface IPs.
     * `topo`  : json file data
-    * `router` : router for which hightest interface should be calculated
+    * `router` : router for which highest interface should be calculated
     """
 
     link_data = topo["routers"][router]["links"]
@@ -1284,7 +1495,6 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, return_is_dict
             _wait = kwargs.pop("wait", wait)
             _attempts = kwargs.pop("attempts", attempts)
             _attempts = int(_attempts)
-            expected = True
             if _attempts < 0:
                 raise ValueError("attempts must be 0 or greater")
 
@@ -1294,12 +1504,10 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, return_is_dict
 
             _return_is_str = kwargs.pop("return_is_str", return_is_str)
             _return_is_dict = kwargs.pop("return_is_str", return_is_dict)
+            _expected = kwargs.setdefault("expected", True)
+            kwargs.pop("expected")
             for i in range(1, _attempts + 1):
                 try:
-                    _expected = kwargs.setdefault("expected", True)
-                    if _expected is False:
-                        expected = _expected
-                    kwargs.pop("expected")
                     ret = func(*args, **kwargs)
                     logger.debug("Function returned %s", ret)
                     if _return_is_str and isinstance(ret, bool) and _expected:
@@ -1311,11 +1519,11 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, return_is_dict
                     if _return_is_dict and isinstance(ret, dict):
                         return ret
 
-                    if _attempts == i and expected:
+                    if _attempts == i:
                         generate_support_bundle()
                         return ret
                 except Exception as err:
-                    if _attempts == i and expected:
+                    if _attempts == i:
                         generate_support_bundle()
                         logger.info("Max number of attempts (%r) reached", _attempts)
                         raise
@@ -1357,6 +1565,17 @@ def step(msg, reset=False):
     _step(msg, reset)
 
 
+def do_countdown(secs):
+    """
+    Countdown timer display
+    """
+    for i in range(secs, 0, -1):
+        sys.stdout.write("{} ".format(str(i)))
+        sys.stdout.flush()
+        sleep(1)
+    return
+
+
 #############################################
 # These APIs,  will used by testcase
 #############################################
@@ -1440,7 +1659,7 @@ def create_interfaces_cfg(tgen, topo, build=False):
                             interface_data.append("no ip ospf " " hello-interval")
                         else:
                             interface_data.append(
-                                "ip ospf " " hello-interval {}".format(intf_ospf_hello)
+                                "ip ospf" " hello-interval {}".format(intf_ospf_hello)
                             )
 
                     if "dead_interval" in ospf_data:
@@ -1451,7 +1670,7 @@ def create_interfaces_cfg(tgen, topo, build=False):
                             interface_data.append("no ip ospf" " dead-interval")
                         else:
                             interface_data.append(
-                                "ip ospf " " dead-interval {}".format(intf_ospf_dead)
+                                "ip ospf" " dead-interval {}".format(intf_ospf_dead)
                             )
 
                     if "network" in ospf_data:
@@ -2219,9 +2438,9 @@ def shutdown_bringup_interface(tgen, dut, intf_name, ifaceaction=False):
     -----
     dut = "r3"
     intf = "r3-r1-eth0"
-    # Shut down ineterface
+    # Shut down interface
     shutdown_bringup_interface(tgen, dut, intf, False)
-    # Bring up ineterface
+    # Bring up interface
     shutdown_bringup_interface(tgen, dut, intf, True)
     Returns
     -------
@@ -2230,13 +2449,58 @@ def shutdown_bringup_interface(tgen, dut, intf_name, ifaceaction=False):
 
     router_list = tgen.routers()
     if ifaceaction:
-        logger.info("Bringing up interface : {}".format(intf_name))
+        logger.info("Bringing up interface {} : {}".format(dut, intf_name))
     else:
-        logger.info("Shutting down interface : {}".format(intf_name))
+        logger.info("Shutting down interface {} : {}".format(dut, intf_name))
 
     interface_set_status(router_list[dut], intf_name, ifaceaction)
 
 
+def stop_router(tgen, router):
+    """
+    Router's current config would be saved to /tmp/topotest/<suite>/<router>
+    for each daemon and router and its daemons would be stopped.
+
+    * `tgen`  : topogen object
+    * `router`: Device under test
+    """
+
+    router_list = tgen.routers()
+
+    # Saving router config to /etc/frr, which will be loaded to router
+    # when it starts
+    router_list[router].vtysh_cmd("write memory")
+
+    # Stop router
+    router_list[router].stop()
+
+
+def start_router(tgen, router):
+    """
+    Router will be started and config would be loaded from
+    /tmp/topotest/<suite>/<router> for each daemon
+
+    * `tgen`  : topogen object
+    * `router`: Device under test
+    """
+
+    logger.debug("Entering lib API: start_router")
+
+    try:
+        router_list = tgen.routers()
+
+        # Router and its daemons would be started and config would
+        #  be loaded to router for each daemon from /etc/frr
+        router_list[router].start()
+
+    except Exception as e:
+        errormsg = traceback.format_exc()
+        logger.error(errormsg)
+        return errormsg
+
+    logger.debug("Exiting lib API: start_router()")
+
+
 def addKernelRoute(
     tgen, router, intf, group_addr_range, next_hop=None, src=None, del_action=None
 ):
@@ -2247,7 +2511,7 @@ def addKernelRoute(
     -----------
     * `tgen`  : Topogen object
     * `router`: router for which kernal routes needs to be added
-    * `intf`: interface name, for which kernal routes needs to be added
+    * `intf`: interface name, for which kernel routes needs to be added
     * `bindToAddress`: bind to <host>, an interface or multicast
                        address
 
@@ -2310,7 +2574,7 @@ def configure_vxlan(tgen, input_dict):
     """
     Add and configure vxlan
 
-    * `tgen`: tgen onject
+    * `tgen`: tgen object
     * `input_dict` : data for vxlan config
 
     Usage:
@@ -2411,7 +2675,7 @@ def configure_brctl(tgen, topo, input_dict):
     """
     Add and configure brctl
 
-    * `tgen`: tgen onject
+    * `tgen`: tgen object
     * `input_dict` : data for brctl config
 
     Usage:
@@ -2505,7 +2769,7 @@ def configure_interface_mac(tgen, input_dict):
     """
     Add and configure brctl
 
-    * `tgen`: tgen onject
+    * `tgen`: tgen object
     * `input_dict` : data for mac config
 
     input_mac= {
@@ -2559,7 +2823,7 @@ def verify_rib(
     tag=None,
     metric=None,
     fib=None,
-    count_only=False
+    count_only=False,
 ):
     """
     Data will be read from input_dict or input JSON file, API will generate
@@ -2751,8 +3015,10 @@ def verify_rib(
                                             "Nexthops are missing for "
                                             "route {} in RIB of router {}: "
                                             "expected {}, found {}\n".format(
-                                                st_rt, dut, len(next_hop),
-                                                len(found_hops)
+                                                st_rt,
+                                                dut,
+                                                len(next_hop),
+                                                len(found_hops),
                                             )
                                         )
                                         return errormsg
@@ -2799,7 +3065,11 @@ def verify_rib(
                                     errormsg = (
                                         "[DUT: {}]: tag value {}"
                                         " is not matched for"
-                                        " route {} in RIB \n".format(dut, _tag, st_rt,)
+                                        " route {} in RIB \n".format(
+                                            dut,
+                                            _tag,
+                                            st_rt,
+                                        )
                                     )
                                     return errormsg
 
@@ -2816,7 +3086,11 @@ def verify_rib(
                                     errormsg = (
                                         "[DUT: {}]: metric value "
                                         "{} is not matched for "
-                                        "route {} in RIB \n".format(dut, metric, st_rt,)
+                                        "route {} in RIB \n".format(
+                                            dut,
+                                            metric,
+                                            st_rt,
+                                        )
                                     )
                                     return errormsg
 
@@ -2865,7 +3139,9 @@ def verify_rib(
 
                 for advertise_network_dict in advertise_network:
                     if "vrf" in advertise_network_dict:
-                        cmd = "{} vrf {} json".format(command, static_route["vrf"])
+                        cmd = "{} vrf {} json".format(
+                            command, advertise_network_dict["vrf"]
+                        )
                     else:
                         cmd = "{} json".format(command)
 
@@ -2944,6 +3220,7 @@ def verify_rib(
     logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
     return True
 
+
 @retry(attempts=6, wait=2, return_is_str=True)
 def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None):
     """
@@ -3324,7 +3601,12 @@ def verify_prefix_lists(tgen, input_dict):
         for addr_type in prefix_lists_addr:
             if not check_address_types(addr_type):
                 continue
-
+            # show ip prefix list
+            if addr_type == "ipv4":
+                cmd = "show ip prefix-list"
+            else:
+                cmd = "show {} prefix-list".format(addr_type)
+            show_prefix_list = run_frr_cmd(rnode, cmd)
             for prefix_list in prefix_lists_addr[addr_type].keys():
                 if prefix_list in show_prefix_list:
                     errormsg = (
@@ -3547,7 +3829,6 @@ def verify_cli_json(tgen, input_dict):
     """
     API to verify if JSON is available for clis
     command.
-
     Parameters
     ----------
     * `tgen`: topogen object
@@ -3717,7 +3998,6 @@ def verify_vrf_vni(tgen, input_dict):
     """
     API to verify vrf vni details using "show vrf vni json"
     command.
-
     Parameters
     ----------
     * `tgen`: topogen object
@@ -3849,3 +4129,270 @@ def required_linux_kernel_version(required_version):
         )
         return error_msg
     return True
+
+
+def iperfSendIGMPJoin(
+    tgen, server, bindToAddress, l4Type="UDP", join_interval=1, inc_step=0, repeat=0
+):
+    """
+    Run iperf to send IGMP join and traffic
+
+    Parameters:
+    -----------
+    * `tgen`  : Topogen object
+    * `l4Type`: string, one of [ TCP, UDP ]
+    * `server`: iperf server, from where IGMP join would be sent
+    * `bindToAddress`: bind to <host>, an interface or multicast
+                       address
+    * `join_interval`: seconds between periodic bandwidth reports
+    * `inc_step`: increamental steps, by default 0
+    * `repeat`: Repetition of group, by default 0
+
+    returns:
+    --------
+    errormsg or True
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    rnode = tgen.routers()[server]
+
+    iperfArgs = "iperf -s "
+
+    # UDP/TCP
+    if l4Type == "UDP":
+        iperfArgs += "-u "
+
+    iperfCmd = iperfArgs
+    # Group address range to cover
+    if bindToAddress:
+        if type(bindToAddress) is not list:
+            Address = []
+            start = ipaddress.IPv4Address(frr_unicode(bindToAddress))
+
+            Address = [start]
+            next_ip = start
+
+            count = 1
+            while count < repeat:
+                next_ip += inc_step
+                Address.append(next_ip)
+                count += 1
+            bindToAddress = Address
+
+    for bindTo in bindToAddress:
+        iperfArgs = iperfCmd
+        iperfArgs += "-B %s " % bindTo
+
+        # Join interval
+        if join_interval:
+            iperfArgs += "-i %d " % join_interval
+
+        iperfArgs += " &>/dev/null &"
+        # Run iperf command to send IGMP join
+        logger.debug("[DUT: {}]: Running command: [{}]".format(server, iperfArgs))
+        output = rnode.run("set +m; {} sleep 0.5".format(iperfArgs))
+
+        # Check if iperf process is running
+        if output:
+            pid = output.split()[1]
+            rnode.run("touch /var/run/frr/iperf_server.pid")
+            rnode.run("echo %s >> /var/run/frr/iperf_server.pid" % pid)
+        else:
+            errormsg = "IGMP join is not sent for {}. Error: {}".format(bindTo, output)
+            logger.error(output)
+            return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True
+
+
+def iperfSendTraffic(
+    tgen,
+    client,
+    bindToAddress,
+    ttl,
+    time=0,
+    l4Type="UDP",
+    inc_step=0,
+    repeat=0,
+    mappedAddress=None,
+):
+    """
+    Run iperf to send IGMP join and traffic
+
+    Parameters:
+    -----------
+    * `tgen`  : Topogen object
+    * `l4Type`: string, one of [ TCP, UDP ]
+    * `client`: iperf client, from where iperf traffic would be sent
+    * `bindToAddress`: bind to <host>, an interface or multicast
+                       address
+    * `ttl`: time to live
+    * `time`: time in seconds to transmit for
+    * `inc_step`: increamental steps, by default 0
+    * `repeat`: Repetition of group, by default 0
+    * `mappedAddress`: Mapped Interface ip address
+
+    returns:
+    --------
+    errormsg or True
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    rnode = tgen.routers()[client]
+
+    iperfArgs = "iperf -c "
+
+    iperfCmd = iperfArgs
+    # Group address range to cover
+    if bindToAddress:
+        if type(bindToAddress) is not list:
+            Address = []
+            start = ipaddress.IPv4Address(frr_unicode(bindToAddress))
+
+            Address = [start]
+            next_ip = start
+
+            count = 1
+            while count < repeat:
+                next_ip += inc_step
+                Address.append(next_ip)
+                count += 1
+            bindToAddress = Address
+
+    for bindTo in bindToAddress:
+        iperfArgs = iperfCmd
+        iperfArgs += "%s " % bindTo
+
+        # Mapped Interface IP
+        if mappedAddress:
+            iperfArgs += "-B %s " % mappedAddress
+
+        # UDP/TCP
+        if l4Type == "UDP":
+            iperfArgs += "-u -b 0.012m "
+
+        # TTL
+        if ttl:
+            iperfArgs += "-T %d " % ttl
+
+        # Time
+        if time:
+            iperfArgs += "-t %d " % time
+
+        iperfArgs += " &>/dev/null &"
+
+        # Run iperf command to send multicast traffic
+        logger.debug("[DUT: {}]: Running command: [{}]".format(client, iperfArgs))
+        output = rnode.run("set +m; {} sleep 0.5".format(iperfArgs))
+
+        # Check if iperf process is running
+        if output:
+            pid = output.split()[1]
+            rnode.run("touch /var/run/frr/iperf_client.pid")
+            rnode.run("echo %s >> /var/run/frr/iperf_client.pid" % pid)
+        else:
+            errormsg = "Multicast traffic is not sent for {}. Error {}".format(
+                bindTo, output
+            )
+            logger.error(output)
+            return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True
+
+
+def kill_iperf(tgen, dut=None, action=None):
+    """
+    Killing iperf process if running for any router in topology
+    Parameters:
+    -----------
+    * `tgen`  : Topogen object
+    * `dut`   : Any iperf hostname to send igmp prune
+    * `action`: to kill igmp join iperf action is remove_join
+                to kill traffic iperf action is remove_traffic
+
+    Usage
+    ----
+    kill_iperf(tgen, dut ="i6", action="remove_join")
+
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    router_list = tgen.routers()
+    for router, rnode in router_list.items():
+        # Run iperf command to send IGMP join
+        pid_client = rnode.run("cat /var/run/frr/iperf_client.pid")
+        pid_server = rnode.run("cat /var/run/frr/iperf_server.pid")
+        if action == "remove_join":
+            pids = pid_server
+        elif action == "remove_traffic":
+            pids = pid_client
+        else:
+            pids = "\n".join([pid_client, pid_server])
+        for pid in pids.split("\n"):
+            pid = pid.strip()
+            if pid.isdigit():
+                cmd = "set +m; kill -9 %s &> /dev/null" % pid
+                logger.debug("[DUT: {}]: Running command: [{}]".format(router, cmd))
+                rnode.run(cmd)
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+
+
+def verify_ip_nht(tgen, input_dict):
+    """
+    Running "show ip nht" command and verifying given nexthop resolution
+    Parameters
+    ----------
+    * `tgen` : topogen object
+    * `input_dict`: data to verify nexthop
+    Usage
+    -----
+    input_dict_4 = {
+            "r1": {
+                nh: {
+                    "Address": nh,
+                    "resolvedVia": "connected",
+                    "nexthops": {
+                        "nexthop1": {
+                            "Interface": intf
+                        }
+                    }
+                }
+            }
+        }
+    result = verify_ip_nht(tgen, input_dict_4)
+    Returns
+    -------
+    errormsg(str) or True
+    """
+
+    logger.debug("Entering lib API: verify_ip_nht()")
+
+    for router in input_dict.keys():
+        if router not in tgen.routers():
+            continue
+
+        rnode = tgen.routers()[router]
+        nh_list = input_dict[router]
+
+        if validate_ip_address(nh_list.keys()[0]) is "ipv6":
+            show_ip_nht = run_frr_cmd(rnode, "show ipv6 nht")
+        else:
+            show_ip_nht = run_frr_cmd(rnode, "show ip nht")
+
+        for nh in nh_list:
+            if nh in show_ip_nht:
+                logger.info("Nexthop %s is resolved on %s", nh, router)
+                return True
+            else:
+                errormsg = "Nexthop {} is resolved on {}".format(nh, router)
+                return errormsg
+
+    logger.debug("Exiting lib API: verify_ip_nht()")
+    return False
+
index 1fb4f48b0f12f76c2b595dad7db0a4e9182e346e..0b6a946fdaf4d2b29075968072ae68bc1346fb99 100644 (file)
@@ -23,7 +23,8 @@ import time
 import datetime
 import json
 import math
-from topolog import logger
+import time
+from lib.topolog import logger
 from mininet.net import Mininet
 
 
@@ -58,14 +59,14 @@ class lUtil:
     def log(self, str, level=6):
         if self.l_level > 0:
             if self.fout == "":
-                self.fout = open(self.fout_name, "w", 0)
+                self.fout = open(self.fout_name, "w")
             self.fout.write(str + "\n")
         if level <= self.l_level:
             print(str)
 
     def summary(self, str):
         if self.fsum == "":
-            self.fsum = open(self.fsum_name, "w", 0)
+            self.fsum = open(self.fsum_name, "w")
             self.fsum.write(
                 "\
 ******************************************************************************\n"
@@ -194,8 +195,9 @@ Total %-4d                                                           %-4d %d\n\
         if op != "wait":
             self.l_line += 1
         self.log(
-            "(#%d) %s:%s COMMAND:%s:%s:%s:%s:%s:"
+            "%s (#%d) %s:%s COMMAND:%s:%s:%s:%s:%s:"
             % (
+                time.asctime(),
                 self.l_total + 1,
                 self.l_filename,
                 self.l_line,
@@ -380,7 +382,8 @@ def luInclude(filename, CallOnFail=None):
         LUtil.setCallOnFail(CallOnFail)
     if filename.endswith(".py"):
         LUtil.log("luInclude: execfile " + tstFile)
-        execfile(tstFile)
+        with open(tstFile) as infile:
+            exec(infile.read())
     else:
         LUtil.log("luInclude: execTestFile " + tstFile)
         LUtil.execTestFile(tstFile)
index 9f3d4841b0075daa21c1739e9bf3ac13d01983ba..3e368cd7d3de3c1865d28c598cc4353adb9714b1 100644 (file)
@@ -62,7 +62,7 @@ def create_router_ospf(tgen, topo, input_dict=None, build=False, load_config=Tru
         "r1": {
             "ospf": {
                 "router_id": "22.22.22.22",
-                "area": [{ "id":0.0.0.0, "type": "nssa"}]
+                "area": [{ "id": "0.0.0.0", "type": "nssa"}]
         }
     }
 
@@ -172,9 +172,6 @@ def __create_ospf_global(tgen, input_dict, router, build=False, load_config=True
                     if del_action:
                         cmd = "no {}".format(cmd)
                     config_data.append(cmd)
-        result = create_common_configuration(
-            tgen, router, config_data, "ospf", build, load_config
-        )
 
         # summary information
         summary_data = ospf_data.setdefault("summary-address", {})
@@ -330,7 +327,7 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config=
                         "links": {
                             "r2": {
                                 "ospf": {
-                                    "authentication": 'message-digest',
+                                    "authentication": "message-digest",
                                     "authentication-key": "ospf",
                                     "message-digest-key": "10"
                                 }
@@ -379,6 +376,7 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config=
             if data_ospf_area:
                 cmd = "ip ospf area {}".format(data_ospf_area)
                 config_data.append(cmd)
+
             # interface ospf auth
             if data_ospf_auth:
                 if data_ospf_auth == "null":
@@ -464,6 +462,32 @@ def clear_ospf(tgen, router):
     logger.debug("Exiting lib API: clear_ospf()")
 
 
+def redistribute_ospf(tgen, topo, dut, route_type, **kwargs):
+    """
+    Redstribution of routes inside ospf.
+
+    Parameters
+    ----------
+    * `tgen`: Topogen object
+    * `topo` : json file data
+    * `dut`: device under test
+    * `route_type`: "static" or "connected" or ....
+    * `kwargs`: pass extra information (see below)
+
+    Usage
+    -----
+    redistribute_ospf(tgen, topo, "r0", "static", delete=True)
+    redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
+    """
+
+    ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": route_type}]}}}
+    for k, v in kwargs.items():
+        ospf_red[dut]["ospf"]["redistribute"][0][k] = v
+
+    result = create_router_ospf(tgen, topo, ospf_red)
+    assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+
 ################################
 # Verification procs
 ################################
@@ -525,7 +549,7 @@ def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
 
             logger.info("Verifying OSPF neighborship on router %s:", router)
             show_ospf_json = run_frr_cmd(
-                rnode, "show ip ospf neighbor  all json", isjson=True
+                rnode, "show ip ospf neighbor all json", isjson=True
             )
 
             # Verifying output dictionary show_ospf_json is empty or not
@@ -847,19 +871,23 @@ def verify_ospf_rib(
                                 if "routeType" not in ospf_rib_json[st_rt]:
                                     errormsg = (
                                         "[DUT: {}]: routeType missing"
-                                        "for route {} in OSPF RIB \n".format(dut, st_rt)
+                                        " for route {} in OSPF RIB \n".format(
+                                            dut, st_rt
+                                        )
                                     )
                                     return errormsg
                                 elif _rtype != ospf_rib_json[st_rt]["routeType"]:
                                     errormsg = (
                                         "[DUT: {}]: routeType mismatch"
-                                        "for route {} in OSPF RIB \n".format(dut, st_rt)
+                                        " for route {} in OSPF RIB \n".format(
+                                            dut, st_rt
+                                        )
                                     )
                                     return errormsg
                                 else:
                                     logger.info(
-                                        "DUT: {}]: Found routeType {}"
-                                        "for route {}".format(dut, _rtype, st_rt)
+                                        "[DUT: {}]: Found routeType {}"
+                                        " for route {}".format(dut, _rtype, st_rt)
                                     )
                             if tag:
                                 if "tag" not in ospf_rib_json[st_rt]:
@@ -874,7 +902,11 @@ def verify_ospf_rib(
                                     errormsg = (
                                         "[DUT: {}]: tag value {}"
                                         " is not matched for"
-                                        " route {} in RIB \n".format(dut, _tag, st_rt,)
+                                        " route {} in RIB \n".format(
+                                            dut,
+                                            _tag,
+                                            st_rt,
+                                        )
                                     )
                                     return errormsg
 
@@ -891,7 +923,11 @@ def verify_ospf_rib(
                                     errormsg = (
                                         "[DUT: {}]: metric value "
                                         "{} is not matched for "
-                                        "route {} in RIB \n".format(dut, metric, st_rt,)
+                                        "route {} in RIB \n".format(
+                                            dut,
+                                            metric,
+                                            st_rt,
+                                        )
                                     )
                                     return errormsg
 
diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py
new file mode 100644 (file)
index 0000000..6bb1326
--- /dev/null
@@ -0,0 +1,3389 @@
+# Copyright (c) 2019 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+import sys
+import os
+import re
+import datetime
+import traceback
+import pytest
+from time import sleep
+from copy import deepcopy
+from lib.topolog import logger
+
+# Import common_config to use commomnly used APIs
+from lib.common_config import (
+    create_common_configuration,
+    InvalidCLIError,
+    retry,
+    run_frr_cmd,
+)
+
+####
+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 on router
+
+    Parameters
+    ----------
+    * `tgen` : Topogen object
+    * `topo` : json file data
+    * `input_dict` : Input dict data, required when configuring from
+                     testcase
+    * `build` : Only for initial setup phase this is set as True.
+
+    Usage
+    -----
+    input_dict = {
+        "r1": {
+            "pim": {
+                "disable" : ["l1-i1-eth1"],
+                "rp": [{
+                    "rp_addr" : "1.0.3.17".
+                    "keep-alive-timer": "100"
+                    "group_addr_range": ["224.1.1.0/24", "225.1.1.0/24"]
+                    "prefix-list": "pf_list_1"
+                    "delete": True
+                }]
+            }
+        }
+    }
+
+
+    Returns
+    -------
+    True or False
+    """
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+    result = False
+    if not input_dict:
+        input_dict = deepcopy(topo)
+    else:
+        topo = topo["routers"]
+        input_dict = deepcopy(input_dict)
+    for router in input_dict.keys():
+        result = _enable_disable_pim(tgen, topo, input_dict, router, build)
+
+        if "pim" not in input_dict[router]:
+            logger.debug("Router %s: 'pim' is not present in " "input_dict", router)
+            continue
+
+        if result is True:
+            if "rp" not in input_dict[router]["pim"]:
+                continue
+
+            result = _create_pim_config(
+                tgen, topo, input_dict, router, build, load_config
+            )
+            if result is not True:
+                return False
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return result
+
+
+def _create_pim_config(tgen, topo, input_dict, router, build=False, load_config=False):
+    """
+    Helper API to create pim configuration.
+
+    Parameters
+    ----------
+    * `tgen` : Topogen object
+    * `topo` : json file data
+    * `input_dict` : Input dict data, required when configuring from testcase
+    * `router` : router id to be configured.
+    * `build` : Only for initial setup phase this is set as True.
+
+    Returns
+    -------
+    True or False
+    """
+
+    result = False
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+    try:
+
+        pim_data = input_dict[router]["pim"]
+
+        for dut in tgen.routers():
+            if "pim" not in input_dict[router]:
+                continue
+
+            for destLink, data in topo[dut]["links"].items():
+                if "pim" not in data:
+                    continue
+
+                if "rp" in pim_data:
+                    config_data = []
+                    rp_data = pim_data["rp"]
+
+                for rp_dict in deepcopy(rp_data):
+                    # ip address of RP
+                    if "rp_addr" not in rp_dict and build:
+                        logger.error(
+                            "Router %s: 'ip address of RP' not "
+                            "present in input_dict/JSON",
+                            router,
+                        )
+
+                        return False
+                    rp_addr = rp_dict.setdefault("rp_addr", None)
+
+                    # Keep alive Timer
+                    keep_alive_timer = rp_dict.setdefault("keep_alive_timer", None)
+
+                    # Group Address range to cover
+                    if "group_addr_range" not in rp_dict and build:
+                        logger.error(
+                            "Router %s:'Group Address range to cover'"
+                            " not present in input_dict/JSON",
+                            router,
+                        )
+
+                        return False
+                    group_addr_range = rp_dict.setdefault("group_addr_range", None)
+
+                    # Group prefix-list filter
+                    prefix_list = rp_dict.setdefault("prefix_list", None)
+
+                    # Delete rp config
+                    del_action = rp_dict.setdefault("delete", False)
+
+                    if keep_alive_timer:
+                        cmd = "ip pim rp keep-alive-timer {}".format(keep_alive_timer)
+                        config_data.append(cmd)
+
+                        if del_action:
+                            cmd = "no {}".format(cmd)
+                            config_data.append(cmd)
+
+                    if rp_addr:
+                        if group_addr_range:
+                            if type(group_addr_range) is not list:
+                                group_addr_range = [group_addr_range]
+
+                            for grp_addr in group_addr_range:
+                                cmd = "ip pim rp {} {}".format(rp_addr, grp_addr)
+                                config_data.append(cmd)
+
+                                if del_action:
+                                    cmd = "no {}".format(cmd)
+                                    config_data.append(cmd)
+
+                        if prefix_list:
+                            cmd = "ip pim rp {} prefix-list {}".format(
+                                rp_addr, prefix_list
+                            )
+                            config_data.append(cmd)
+
+                            if del_action:
+                                cmd = "no {}".format(cmd)
+                                config_data.append(cmd)
+
+            result = create_common_configuration(
+                tgen, dut, config_data, "pim", build, load_config
+            )
+            if result is not True:
+                return False
+
+    except InvalidCLIError:
+        # Traceback
+        errormsg = traceback.format_exc()
+        logger.error(errormsg)
+        return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return result
+
+
+def create_igmp_config(tgen, topo, input_dict=None, build=False):
+    """
+    API to configure igmp on router
+
+    Parameters
+    ----------
+    * `tgen` : Topogen object
+    * `topo` : json file data
+    * `input_dict` : Input dict data, required when configuring from
+                     testcase
+    * `build` : Only for initial setup phase this is set as True.
+
+    Usage
+    -----
+    input_dict = {
+        "r1": {
+            "igmp": {
+                "interfaces": {
+                    "r1-r0-eth0" :{
+                        "igmp":{
+                            "version":  "2",
+                            "delete": True
+                            "query": {
+                                "query-interval" : 100,
+                                "query-max-response-time": 200
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    Returns
+    -------
+    True or False
+    """
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+    result = False
+    if not input_dict:
+        input_dict = deepcopy(topo)
+    else:
+        topo = topo["routers"]
+        input_dict = deepcopy(input_dict)
+    for router in input_dict.keys():
+        if "igmp" not in input_dict[router]:
+            logger.debug("Router %s: 'igmp' is not present in " "input_dict", router)
+            continue
+
+        igmp_data = input_dict[router]["igmp"]
+
+        if "interfaces" in igmp_data:
+            config_data = []
+            intf_data = igmp_data["interfaces"]
+
+            for intf_name in intf_data.keys():
+                cmd = "interface {}".format(intf_name)
+                config_data.append(cmd)
+                protocol = "igmp"
+                del_action = intf_data[intf_name]["igmp"].setdefault("delete", False)
+                cmd = "ip igmp"
+                if del_action:
+                    cmd = "no {}".format(cmd)
+                config_data.append(cmd)
+
+                del_attr = intf_data[intf_name]["igmp"].setdefault("delete_attr", False)
+                for attribute, data in intf_data[intf_name]["igmp"].items():
+                    if attribute == "version":
+                        cmd = "ip {} {} {}".format(protocol, attribute, data)
+                        if del_action:
+                            cmd = "no {}".format(cmd)
+                        config_data.append(cmd)
+
+                    if attribute == "join":
+                        for group in data:
+                            cmd = "ip {} {} {}".format(protocol, attribute, group)
+                            if del_attr:
+                                cmd = "no {}".format(cmd)
+                            config_data.append(cmd)
+
+                    if attribute == "query":
+                        for query, value in data.items():
+                            if query != "delete":
+                                cmd = "ip {} {} {}".format(protocol, query, value)
+
+                                if "delete" in intf_data[intf_name][protocol]["query"]:
+                                    cmd = "no {}".format(cmd)
+
+                            config_data.append(cmd)
+        try:
+
+            result = create_common_configuration(
+                tgen, router, config_data, "interface_config", build=build
+            )
+        except InvalidCLIError:
+            errormsg = traceback.format_exc()
+            logger.error(errormsg)
+            return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return result
+
+
+def _enable_disable_pim(tgen, topo, input_dict, router, build=False):
+    """
+    Helper API to enable or disable pim on interfaces
+
+    Parameters
+    ----------
+    * `tgen` : Topogen object
+    * `topo` : json file data
+    * `input_dict` : Input dict data, required when configuring from testcase
+    * `router` : router id to be configured.
+    * `build` : Only for initial setup phase this is set as True.
+
+    Returns
+    -------
+    True or False
+    """
+    result = False
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+    try:
+        config_data = []
+
+        enable_flag = True
+        # Disable pim on interface
+        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")
+
+        # Enable pim on interface
+        if enable_flag:
+            for destRouterLink, data in sorted(topo[router]["links"].items()):
+                if "pim" in data and data["pim"] == "enable":
+
+                    # Loopback interfaces
+                    if "type" in data and data["type"] == "loopback":
+                        interface_name = destRouterLink
+                    else:
+                        interface_name = data["interface"]
+
+                    cmd = "interface {}".format(interface_name)
+                    config_data.append(cmd)
+                    config_data.append("ip pim")
+
+        result = create_common_configuration(
+            tgen, router, config_data, "interface_config", build=build
+        )
+        if result is not True:
+            return False
+
+    except InvalidCLIError:
+        # Traceback
+        errormsg = traceback.format_exc()
+        logger.error(errormsg)
+        return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return result
+
+
+def add_rp_interfaces_and_pim_config(tgen, topo, interface, rp, rp_mapping):
+    """
+    Add physical interfaces tp RP for all the RPs
+
+    Parameters
+    ----------
+    * `tgen` : Topogen object
+    * `topo` : json file data
+    * `interface` : RP interface
+    * `rp` : rp for given topology
+    * `rp_mapping` : dictionary of all groups and RPs
+
+    Returns
+    -------
+    True or False
+    """
+    result = False
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    try:
+        config_data = []
+
+        for group, rp_list in rp_mapping.items():
+            for _rp in rp_list:
+                config_data.append("interface {}".format(interface))
+                config_data.append("ip address {}".format(_rp))
+                config_data.append("ip pim")
+
+            result = create_common_configuration(
+                tgen, rp, config_data, "interface_config"
+            )
+            if result is not True:
+                return False
+
+    except InvalidCLIError:
+        # Traceback
+        errormsg = traceback.format_exc()
+        logger.error(errormsg)
+        return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return result
+
+
+def find_rp_details(tgen, topo):
+    """
+    Find who is RP in topology and returns list of RPs
+
+    Parameters:
+    -----------
+    * `tgen` : Topogen object
+    * `topo` : json file data
+
+    returns:
+    --------
+    errormsg or True
+    """
+
+    rp_details = {}
+
+    router_list = tgen.routers()
+    topo_data = topo["routers"]
+
+    for router in router_list.keys():
+
+        if "pim" not in topo_data[router]:
+            continue
+
+        pim_data = topo_data[router]["pim"]
+        if "rp" in pim_data:
+            rp_data = pim_data["rp"]
+            for rp_dict in rp_data:
+                # ip address of RP
+                rp_addr = rp_dict["rp_addr"]
+
+                for link, data in topo["routers"][router]["links"].items():
+                    if data["ipv4"].split("/")[0] == rp_addr:
+                        rp_details[router] = rp_addr
+
+    return rp_details
+
+
+def configure_pim_force_expire(tgen, topo, input_dict, build=False):
+    """
+    Helper API to create pim configuration.
+
+    Parameters
+    ----------
+    * `tgen` : Topogen object
+    * `topo` : json file data
+    * `input_dict` : Input dict data, required when configuring from testcase
+    * `build` : Only for initial setup phase this is set as True.
+
+    Usage
+    -----
+    input_dict ={
+        "l1": {
+            "pim": {
+                "force_expire":{
+                    "10.0.10.1": ["255.1.1.1"]
+                }
+            }
+        }
+    }
+
+    result = create_pim_config(tgen, topo, input_dict)
+
+    Returns
+    -------
+    True or False
+    """
+
+    result = False
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+    try:
+
+        for dut in input_dict.keys():
+            if "pim" not in input_dict[dut]:
+                continue
+
+            pim_data = input_dict[dut]["pim"]
+
+            if "force_expire" in pim_data:
+                config_data = []
+                force_expire_data = pim_data["force_expire"]
+
+                for source, groups in force_expire_data.items():
+                    if type(groups) is not list:
+                        groups = [groups]
+
+                    for group in groups:
+                        cmd = "ip pim force-expire source {} group {}".format(
+                            source, group
+                        )
+                        config_data.append(cmd)
+
+                    result = create_common_configuration(
+                        tgen, dut, config_data, "pim", build=build
+                    )
+                    if result is not True:
+                        return False
+
+    except InvalidCLIError:
+        # Traceback
+        errormsg = traceback.format_exc()
+        logger.error(errormsg)
+        return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return result
+
+
+#############################################
+# Verification APIs
+#############################################
+def verify_pim_neighbors(tgen, topo, dut=None, iface=None):
+    """
+    Verify all PIM neighbors are up and running, config is verified
+    using "show ip pim neighbor" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `topo` : json file data
+    * `dut` : dut info
+    * `iface` : link for which PIM nbr need to check
+
+    Usage
+    -----
+    result = verify_pim_neighbors(tgen, topo, dut, link)
+
+    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 ip pim neighbor json", isjson=True
+        )
+
+        for destLink, data in topo["routers"][router]["links"].items():
+            if iface is not None and iface != data["interface"]:
+                continue
+
+            if "type" in data and data["type"] == "loopback":
+                continue
+
+            if "pim" not in data:
+                continue
+
+            if "pim" in data and data["pim"] == "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]
+            if "type" in data and data["type"] == "loopback":
+                continue
+
+            if "pim" not in data:
+                continue
+
+            logger.info("[DUT: %s]: Verifying PIM neighbor status:", router)
+
+            if "pim" in data and data["pim"] == "enable":
+                pim_nh_intf_ip = data["ipv4"].split("/")[0]
+
+                # 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, PIM"
+                                " 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 PIM neighbor %s",
+                            router,
+                            local_interface,
+                            pim_nh_intf_ip,
+                        )
+                    else:
+                        errormsg = (
+                            "[DUT %s]: Local interface: %s, and"
+                            "interface ip: %s is not found in "
+                            "PIM neighbor " % (router, local_interface, pim_nh_intf_ip)
+                        )
+                        return errormsg
+                else:
+                    errormsg = (
+                        "[DUT %s]: Local interface: %s, is not "
+                        "present in PIM neighbor " % (router, local_interface)
+                    )
+                    return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True
+
+
+@retry(attempts=21, wait=2, return_is_str=True)
+def verify_igmp_groups(tgen, dut, interface, group_addresses):
+    """
+    Verify IGMP groups are received from an intended interface
+    by running "show ip igmp groups" command
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `dut`: device under test
+    * `interface`: interface, from which IGMP groups would be received
+    * `group_addresses`: IGMP group address
+
+    Usage
+    -----
+    dut = "r1"
+    interface = "r1-r0-eth0"
+    group_address = "225.1.1.1"
+    result = verify_igmp_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 IGMP groups received:", dut)
+    show_ip_igmp_json = run_frr_cmd(rnode, "show ip igmp groups json", isjson=True)
+
+    if type(group_addresses) is not list:
+        group_addresses = [group_addresses]
+
+    if interface in show_ip_igmp_json:
+        show_ip_igmp_json = show_ip_igmp_json[interface]["groups"]
+    else:
+        errormsg = (
+            "[DUT %s]: Verifying IGMP group received"
+            " from interface %s [FAILED]!! " % (dut, interface)
+        )
+        return errormsg
+
+    found = False
+    for grp_addr in group_addresses:
+        for index in show_ip_igmp_json:
+            if index["group"] == grp_addr:
+                found = True
+                break
+        if found is not True:
+            errormsg = (
+                "[DUT %s]: Verifying IGMP group received"
+                " from interface %s [FAILED]!! "
+                " Expected not found: %s" % (dut, interface, grp_addr)
+            )
+            return errormsg
+
+        logger.info(
+            "[DUT %s]: Verifying IGMP 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(attempts=31, wait=2, return_is_str=True)
+def verify_upstream_iif(
+    tgen, dut, iif, src_address, group_addresses, joinState=None, refCount=1
+):
+    """
+    Verify upstream inbound interface  is updated correctly
+    by running "show ip pim upstream" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `dut`: device under test
+    * `iif`: inbound interface
+    * `src_address`: source address
+    * `group_addresses`: IGMP group address
+    * `joinState`: upstream join state
+    * `refCount`: refCount value
+
+    Usage
+    -----
+    dut = "r1"
+    iif = "r1-r0-eth0"
+    src_address = "*"
+    group_address = "225.1.1.1"
+    result = verify_upstream_iif(tgen, dut, iif, src_address, group_address,
+                                state, refCount)
+
+    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 upstream Inbound Interface" " for IGMP groups received:",
+        dut,
+    )
+    show_ip_pim_upstream_json = run_frr_cmd(
+        rnode, "show ip pim upstream json", isjson=True
+    )
+
+    if type(group_addresses) is not list:
+        group_addresses = [group_addresses]
+
+    if type(iif) is not list:
+        iif = [iif]
+
+    for grp_addr in group_addresses:
+        # Verify group address
+        if grp_addr not in show_ip_pim_upstream_json:
+            errormsg = "[DUT %s]: Verifying upstream" " for group %s [FAILED]!!" % (
+                dut,
+                grp_addr,
+            )
+            return errormsg
+        group_addr_json = show_ip_pim_upstream_json[grp_addr]
+
+        # Verify source address
+        if src_address not in group_addr_json:
+            errormsg = "[DUT %s]: Verifying upstream" " for (%s,%s) [FAILED]!!" % (
+                dut,
+                src_address,
+                grp_addr,
+            )
+            return errormsg
+
+        # Verify Inbound Interface
+        found = False
+        for in_interface in iif:
+            if group_addr_json[src_address]["inboundInterface"] == in_interface:
+                if refCount > 0:
+                    logger.info(
+                        "[DUT %s]: Verifying refCount "
+                        "for (%s,%s) [PASSED]!! "
+                        " Found Expected: %s",
+                        dut,
+                        src_address,
+                        grp_addr,
+                        group_addr_json[src_address]["refCount"],
+                    )
+                    found = True
+                if found:
+                    if joinState is None:
+                        if group_addr_json[src_address]["joinState"] != "Joined":
+                            errormsg = (
+                                "[DUT %s]: Verifying iif "
+                                "(Inbound Interface) for (%s,%s) and"
+                                " joinState :%s [FAILED]!! "
+                                " Expected: %s, Found: %s"
+                                % (
+                                    dut,
+                                    src_address,
+                                    grp_addr,
+                                    group_addr_json[src_address]["joinState"],
+                                    in_interface,
+                                    group_addr_json[src_address]["inboundInterface"],
+                                )
+                            )
+                            return errormsg
+
+                    elif group_addr_json[src_address]["joinState"] != joinState:
+                        errormsg = (
+                            "[DUT %s]: Verifying iif "
+                            "(Inbound Interface) for (%s,%s) and"
+                            " joinState :%s [FAILED]!! "
+                            " Expected: %s, Found: %s"
+                            % (
+                                dut,
+                                src_address,
+                                grp_addr,
+                                group_addr_json[src_address]["joinState"],
+                                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]!! "
+                        " Found Expected: (%s)",
+                        dut,
+                        src_address,
+                        grp_addr,
+                        group_addr_json[src_address]["joinState"],
+                        group_addr_json[src_address]["inboundInterface"],
+                    )
+        if not found:
+            errormsg = (
+                "[DUT %s]: Verifying iif "
+                "(Inbound Interface) for (%s, %s) "
+                "[FAILED]!! "
+                " Expected: %s, Found: %s"
+                % (
+                    dut,
+                    src_address,
+                    grp_addr,
+                    in_interface,
+                    group_addr_json[src_address]["inboundInterface"],
+                )
+            )
+            return errormsg
+
+        logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+        return True
+
+
+@retry(attempts=6, wait=2, return_is_str=True)
+def verify_join_state_and_timer(tgen, dut, iif, src_address, group_addresses):
+    """
+    Verify  join state is updated correctly and join timer is
+    running with the help of "show ip pim upstream" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `dut`: device under test
+    * `iif`: inbound interface
+    * `src_address`: source address
+    * `group_addresses`: IGMP group address
+
+    Usage
+    -----
+    dut = "r1"
+    iif = "r1-r0-eth0"
+    group_address = "225.1.1.1"
+    result = verify_join_state_and_timer(tgen, dut, iif, group_address)
+
+    Returns
+    -------
+    errormsg(str) or True
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+    errormsg = ""
+
+    if dut not in tgen.routers():
+        return False
+
+    rnode = tgen.routers()[dut]
+
+    logger.info(
+        "[DUT: %s]: Verifying Join state and Join Timer" " for IGMP groups received:",
+        dut,
+    )
+    show_ip_pim_upstream_json = run_frr_cmd(
+        rnode, "show ip pim upstream json", isjson=True
+    )
+
+    if type(group_addresses) is not list:
+        group_addresses = [group_addresses]
+
+    for grp_addr in group_addresses:
+        # Verify group address
+        if grp_addr not in show_ip_pim_upstream_json:
+            errormsg = "[DUT %s]: Verifying upstream" " for group %s [FAILED]!!" % (
+                dut,
+                grp_addr,
+            )
+            return errormsg
+
+        group_addr_json = show_ip_pim_upstream_json[grp_addr]
+
+        # Verify source address
+        if src_address not in group_addr_json:
+            errormsg = "[DUT %s]: Verifying upstream" " for (%s,%s) [FAILED]!!" % (
+                dut,
+                src_address,
+                grp_addr,
+            )
+            return errormsg
+
+        # Verify join state
+        joinState = group_addr_json[src_address]["joinState"]
+        if joinState != "Joined":
+            error = (
+                "[DUT %s]: Verifying join state for"
+                " (%s,%s) [FAILED]!! "
+                " Expected: %s, Found: %s"
+                % (dut, src_address, grp_addr, "Joined", joinState)
+            )
+            errormsg = errormsg + "\n" + str(error)
+        else:
+            logger.info(
+                "[DUT %s]: Verifying join state for"
+                " (%s,%s) [PASSED]!! "
+                " Found Expected: %s",
+                dut,
+                src_address,
+                grp_addr,
+                joinState,
+            )
+
+        # Verify join timer
+        joinTimer = group_addr_json[src_address]["joinTimer"]
+        if not re.match(r"(\d{2}):(\d{2}):(\d{2})", joinTimer):
+            error = (
+                "[DUT %s]: Verifying join timer for"
+                " (%s,%s) [FAILED]!! "
+                " Expected: %s, Found: %s",
+                dut,
+                src_address,
+                grp_addr,
+                "join timer should be running",
+                joinTimer,
+            )
+            errormsg = errormsg + "\n" + str(error)
+        else:
+            logger.info(
+                "[DUT %s]: Verifying join timer is running"
+                " for (%s,%s) [PASSED]!! "
+                " Found Expected: %s",
+                dut,
+                src_address,
+                grp_addr,
+                joinTimer,
+            )
+
+        if errormsg != "":
+            return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True
+
+
+@retry(attempts=41, wait=2, return_is_dict=True)
+def verify_ip_mroutes(
+    tgen, dut, src_address, group_addresses, iif, oil, return_uptime=False, mwait=0
+):
+    """
+    Verify ip mroutes and make sure (*, G)/(S, G) is present in mroutes
+    by running "show ip pim upstream" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `dut`: device under test
+    * `src_address`: source address
+    * `group_addresses`: IGMP group address
+    * `iif`: Incoming interface
+    * `oil`: Outgoing interface
+    * `return_uptime`: If True, return uptime dict, default is False
+    * `mwait`: Wait time, default is 0
+
+
+    Usage
+    -----
+    dut = "r1"
+    group_address = "225.1.1.1"
+    result = verify_ip_mroutes(tgen, dut, src_address, 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]
+
+    if return_uptime:
+        logger.info("Sleeping for %s sec..", mwait)
+        sleep(mwait)
+
+    logger.info("[DUT: %s]: Verifying ip mroutes", dut)
+    show_ip_mroute_json = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
+
+    if return_uptime:
+        uptime_dict = {}
+
+    if bool(show_ip_mroute_json) == False:
+        error_msg = "[DUT %s]: mroutes are not present or flushed out !!" % (dut)
+        return error_msg
+
+    if not isinstance(group_addresses, list):
+        group_addresses = [group_addresses]
+
+    if not isinstance(iif, list) and iif is not "none":
+        iif = [iif]
+
+    if not isinstance(oil, list) and oil is not "none":
+        oil = [oil]
+
+    for grp_addr in group_addresses:
+        if grp_addr not in show_ip_mroute_json:
+            errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
+                dut,
+                src_address,
+                grp_addr,
+            )
+            return errormsg
+        else:
+            if return_uptime:
+                uptime_dict[grp_addr] = {}
+
+            group_addr_json = show_ip_mroute_json[grp_addr]
+
+        if src_address not in group_addr_json:
+            errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
+                dut,
+                src_address,
+                grp_addr,
+            )
+            return errormsg
+        else:
+            if return_uptime:
+                uptime_dict[grp_addr][src_address] = {}
+
+            mroutes = group_addr_json[src_address]
+
+        if mroutes["installed"] != 0:
+            logger.info(
+                "[DUT %s]: mroute (%s,%s) is installed", dut, src_address, grp_addr
+            )
+
+            if "oil" not in mroutes:
+                if oil == "none" and mroutes["iif"] in iif:
+                    logger.info(
+                        "[DUT %s]: Verifying (%s, %s) mroute,"
+                        " [PASSED]!!  Found Expected: "
+                        "(iif: %s, oil: %s, installed: (%s,%s))",
+                        dut,
+                        src_address,
+                        grp_addr,
+                        mroutes["iif"],
+                        oil,
+                        src_address,
+                        grp_addr,
+                    )
+                else:
+                    errormsg = (
+                        "[DUT %s]: Verifying (%s, %s) mroute,"
+                        " [FAILED]!! "
+                        "Expected: (oil: %s, installed:"
+                        " (%s,%s)) Found: ( oil: none, "
+                        "installed: (%s,%s))"
+                        % (
+                            dut,
+                            src_address,
+                            grp_addr,
+                            oil,
+                            src_address,
+                            grp_addr,
+                            src_address,
+                            grp_addr,
+                        )
+                    )
+
+                    return errormsg
+
+            else:
+                found = False
+                for route, data in mroutes["oil"].items():
+                    if route in oil and route != "pimreg":
+                        if (
+                            data["source"] == src_address
+                            and data["group"] == grp_addr
+                            and data["inboundInterface"] in iif
+                            and data["outboundInterface"] in oil
+                        ):
+                            if return_uptime:
+
+                                uptime_dict[grp_addr][src_address] = data["upTime"]
+
+                            logger.info(
+                                "[DUT %s]: Verifying (%s, %s)"
+                                " mroute, [PASSED]!!  "
+                                "Found Expected: "
+                                "(iif: %s, oil: %s, installed:"
+                                " (%s,%s)",
+                                dut,
+                                src_address,
+                                grp_addr,
+                                data["inboundInterface"],
+                                data["outboundInterface"],
+                                data["source"],
+                                data["group"],
+                            )
+                            found = True
+                            break
+                    else:
+                        continue
+
+                if not found:
+                    errormsg = (
+                        "[DUT %s]: Verifying (%s, %s)"
+                        " mroute [FAILED]!! "
+                        "Expected in: (iif: %s, oil: %s,"
+                        " installed: (%s,%s)) Found: "
+                        "(iif: %s, oil: %s, "
+                        "installed: (%s,%s))"
+                        % (
+                            dut,
+                            src_address,
+                            grp_addr,
+                            iif,
+                            oil,
+                            src_address,
+                            grp_addr,
+                            data["inboundInterface"],
+                            data["outboundInterface"],
+                            data["source"],
+                            data["group"],
+                        )
+                    )
+                    return errormsg
+
+        else:
+            errormsg = "[DUT %s]: mroute (%s,%s) is not installed" % (
+                dut,
+                src_address,
+                grp_addr,
+            )
+            return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True if return_uptime == False else uptime_dict
+
+
+@retry(attempts=31, wait=2, return_is_str=True)
+def verify_pim_rp_info(
+    tgen, topo, dut, group_addresses, oif=None, rp=None, source=None, iamrp=None
+):
+    """
+    Verify pim rp info by running "show ip pim rp-info" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `topo`: JSON file handler
+    * `dut`: device under test
+    * `group_addresses`: IGMP group address
+    * `oif`: outbound interface name
+    * `rp`: RP address
+    * `source`: Source of RP
+    * `iamrp`: User defined RP
+
+    Usage
+    -----
+    dut = "r1"
+    result = verify_pim_rp_info(tgen, topo, dut, group_address,
+                                rp=rp, source="BSR")
+
+    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 ip rp info", dut)
+    show_ip_rp_info_json = run_frr_cmd(rnode, "show ip pim rp-info json", isjson=True)
+
+    if type(group_addresses) is not list:
+        group_addresses = [group_addresses]
+
+    if type(oif) is not list:
+        oif = [oif]
+
+    for grp_addr in group_addresses:
+        if rp is None:
+            rp_details = find_rp_details(tgen, topo)
+
+            if dut in rp_details:
+                iamRP = True
+            else:
+                iamRP = False
+        else:
+            show_ip_route_json = run_frr_cmd(
+                rnode, "show ip route connected json", isjson=True
+            )
+            for _rp in show_ip_route_json.keys():
+                if rp == _rp.split("/")[0]:
+                    iamRP = True
+                    break
+                else:
+                    iamRP = False
+
+        if rp not in show_ip_rp_info_json:
+            errormsg = "[DUT %s]: Verifying rp-info" "for rp_address %s [FAILED]!! " % (
+                dut,
+                rp,
+            )
+            return errormsg
+        else:
+            group_addr_json = show_ip_rp_info_json[rp]
+
+        for rp_json in group_addr_json:
+            if oif is not None:
+                found = False
+                if rp_json["outboundInterface"] not in oif:
+                    errormsg = (
+                        "[DUT %s]: Verifying OIF "
+                        "for group %s and RP %s [FAILED]!! "
+                        "Expected interfaces: (%s),"
+                        " Found: (%s)"
+                        % (dut, grp_addr, rp, oif, rp_json["outboundInterface"])
+                    )
+                    return errormsg
+
+                logger.info(
+                    "[DUT %s]: Verifying OIF "
+                    "for group %s and RP %s [PASSED]!! "
+                    "Found Expected: (%s)"
+                    % (dut, grp_addr, rp, rp_json["outboundInterface"])
+                )
+
+            if source is not None:
+                if rp_json["source"] != source:
+                    errormsg = (
+                        "[DUT %s]: Verifying SOURCE "
+                        "for group %s and RP %s [FAILED]!! "
+                        "Expected: (%s),"
+                        " Found: (%s)" % (dut, grp_addr, rp, source, rp_json["source"])
+                    )
+                    return errormsg
+
+                logger.info(
+                    "[DUT %s]: Verifying SOURCE "
+                    "for group %s and RP %s [PASSED]!! "
+                    "Found Expected: (%s)" % (dut, grp_addr, rp, rp_json["source"])
+                )
+
+            if rp_json["group"] == grp_addr and iamrp is not None:
+                if iamRP:
+                    if rp_json["iAmRP"]:
+                        logger.info(
+                            "[DUT %s]: Verifying group "
+                            "and iAmRP [PASSED]!!"
+                            " Found Expected: (%s, %s:%s)",
+                            dut,
+                            grp_addr,
+                            "iAmRP",
+                            rp_json["iAmRP"],
+                        )
+                    else:
+                        errormsg = (
+                            "[DUT %s]: Verifying group"
+                            "%s and iAmRP [FAILED]!! "
+                            "Expected: (iAmRP: %s),"
+                            " Found: (iAmRP: %s)"
+                            % (dut, grp_addr, "true", rp_json["iAmRP"])
+                        )
+                        return errormsg
+
+            if not iamRP:
+                if rp_json["iAmRP"] == False:
+                    logger.info(
+                        "[DUT %s]: Verifying group "
+                        "and iAmNotRP [PASSED]!!"
+                        " Found Expected: (%s, %s:%s)",
+                        dut,
+                        grp_addr,
+                        "iAmRP",
+                        rp_json["iAmRP"],
+                    )
+                else:
+                    errormsg = (
+                        "[DUT %s]: Verifying group"
+                        "%s and iAmRP [FAILED]!! "
+                        "Expected: (iAmRP: %s),"
+                        " Found: (iAmRP: %s)"
+                        % (dut, grp_addr, "false", rp_json["iAmRP"])
+                    )
+                    return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True
+
+
+@retry(attempts=31, wait=2, return_is_str=True)
+def verify_pim_state(
+    tgen, dut, iif, oil, group_addresses, src_address=None, installed_fl=None
+):
+    """
+    Verify pim state by running "show ip pim state" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `dut`: device under test
+    * `iif`: inbound interface
+    * `oil`: outbound interface
+    * `group_addresses`: IGMP group address
+    * `src_address`: source address, default = None
+    * installed_fl` : Installed flag
+
+    Usage
+    -----
+    dut = "r1"
+    iif = "r1-r3-eth1"
+    oil = "r1-r0-eth0"
+    group_address = "225.1.1.1"
+    result = verify_pim_state(tgen, dut, iif, oil, 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 pim state", dut)
+    show_pim_state_json = run_frr_cmd(rnode, "show ip pim state json", isjson=True)
+
+    if installed_fl is None:
+        installed_fl = 1
+
+    if type(group_addresses) is not list:
+        group_addresses = [group_addresses]
+
+    for grp_addr in group_addresses:
+        if src_address is None:
+            src_address = "*"
+            pim_state_json = show_pim_state_json[grp_addr][src_address]
+        else:
+            pim_state_json = show_pim_state_json[grp_addr][src_address]
+
+        if pim_state_json["Installed"] == installed_fl:
+            logger.info(
+                "[DUT %s]: group  %s is installed flag: %s",
+                dut,
+                grp_addr,
+                pim_state_json["Installed"],
+            )
+            for interface, data in pim_state_json[iif].items():
+                if interface != oil:
+                    continue
+
+                # Verify iif, oil and installed state
+                if (
+                    data["group"] == grp_addr
+                    and data["installed"] == installed_fl
+                    and data["inboundInterface"] == iif
+                    and data["outboundInterface"] == oil
+                ):
+                    logger.info(
+                        "[DUT %s]: Verifying pim state for group"
+                        " %s [PASSED]!! Found Expected: "
+                        "(iif: %s, oil: %s, installed: %s) ",
+                        dut,
+                        grp_addr,
+                        data["inboundInterface"],
+                        data["outboundInterface"],
+                        data["installed"],
+                    )
+                else:
+                    errormsg = (
+                        "[DUT %s]: Verifying pim state for group"
+                        " %s, [FAILED]!! Expected: "
+                        "(iif: %s, oil: %s, installed: %s) ",
+                        "Found: (iif: %s, oil: %s, installed: %s)"
+                        % (
+                            dut,
+                            grp_addr,
+                            iif,
+                            oil,
+                            "1",
+                            data["inboundInterface"],
+                            data["outboundInterface"],
+                            data["installed"],
+                        ),
+                    )
+                    return errormsg
+        else:
+            errormsg = "[DUT %s]: %s install flag value not as expected" % (
+                dut,
+                grp_addr,
+            )
+            return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True
+
+
+def verify_pim_interface_traffic(tgen, input_dict):
+    """
+    Verify ip pim interface traffice by running
+    "show ip pim interface traffic" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `input_dict(dict)`: defines DUT, what and from which interfaces
+                          traffic needs to be verified
+    Usage
+    -----
+    input_dict = {
+        "r1": {
+            "r1-r0-eth0": {
+                "helloRx": 0,
+                "helloTx": 1,
+                "joinRx": 0,
+                "joinTx": 0
+            }
+        }
+    }
+
+    result = verify_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)
+        show_pim_intf_traffic_json = run_frr_cmd(
+            rnode, "show ip 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
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return output_dict
+
+
+@retry(attempts=31, wait=2, return_is_str=True)
+def verify_pim_interface(tgen, topo, dut):
+    """
+    Verify all PIM interface are up and running, config is verified
+    using "show ip pim interface" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `topo` : json file data
+    * `dut` : device under test
+
+    Usage
+    -----
+    result = verify_pim_interfacetgen, topo, dut)
+
+    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 PIM interface status:", dut)
+
+        rnode = tgen.routers()[dut]
+        show_ip_pim_interface_json = run_frr_cmd(
+            rnode, "show ip pim interface json", isjson=True
+        )
+
+        for destLink, data in topo["routers"][dut]["links"].items():
+            if "type" in data and data["type"] == "loopback":
+                continue
+
+            if "pim" in data and data["pim"] == "enable":
+                pim_interface = data["interface"]
+                pim_intf_ip = data["ipv4"].split("/")[0]
+
+                if pim_interface in show_ip_pim_interface_json:
+                    pim_intf_json = show_ip_pim_interface_json[pim_interface]
+
+                    # Verifying PIM interface
+                    if (
+                        pim_intf_json["address"] != pim_intf_ip
+                        and pim_intf_json["state"] != "up"
+                    ):
+                        errormsg = (
+                            "[DUT %s]: PIM interface: %s "
+                            "PIM interface ip: %s, status check "
+                            "[FAILED]!! Expected : %s, Found : %s"
+                            % (
+                                dut,
+                                pim_interface,
+                                pim_intf_ip,
+                                pim_interface,
+                                pim_intf_json["state"],
+                            )
+                        )
+                        return errormsg
+
+                    logger.info(
+                        "[DUT %s]: PIM interface: %s, "
+                        "interface ip: %s, status: %s"
+                        " [PASSED]!!",
+                        dut,
+                        pim_interface,
+                        pim_intf_ip,
+                        pim_intf_json["state"],
+                    )
+                else:
+                    errormsg = (
+                        "[DUT %s]: PIM interface: %s "
+                        "PIM interface ip: %s, is not present "
+                        % (dut, pim_interface, pim_intf_ip,)
+                    )
+                    return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True
+
+
+def clear_ip_pim_interface_traffic(tgen, topo):
+    """
+    Clear ip pim interface traffice by running
+    "clear ip pim interface traffic" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    Usage
+    -----
+
+    result = clear_ip_pim_interface_traffic(tgen, topo)
+
+    Returns
+    -------
+    errormsg(str) or True
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    for dut in tgen.routers():
+        if "pim" not in topo["routers"][dut]:
+            continue
+
+        rnode = tgen.routers()[dut]
+
+        logger.info("[DUT: %s]: Clearing pim interface traffic", dut)
+        result = run_frr_cmd(rnode, "clear ip pim interface traffic")
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+
+    return True
+
+
+def clear_ip_pim_interfaces(tgen, dut):
+    """
+    Clear ip pim interface by running
+    "clear ip pim interfaces" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `dut`: Device Under Test
+    Usage
+    -----
+
+    result = clear_ip_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):
+        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
+                fail_intf.append(pim_intf)
+
+        if found is True:
+            break
+    else:
+        errormsg = (
+            "[DUT: %s]: pim neighborship is not formed for %s"
+            "after clear_ip_pim_interfaces %s [FAILED!!]",
+            dut,
+            fail_intf,
+        )
+        return errormsg
+
+    for key, value in run_json_after.items():
+        if bool(value):
+            for _key, _value in value.items():
+                nh_after_clear[key] = _value["upTime"]
+
+    # Verify uptime for neighbors
+    for pim_intf in nh_before_clear.keys():
+        d1 = datetime.datetime.strptime(nh_before_clear[pim_intf], "%H:%M:%S")
+        d2 = datetime.datetime.strptime(nh_after_clear[pim_intf], "%H:%M:%S")
+        if d2 >= d1:
+            errormsg = (
+                "[DUT: %s]: PIM neighborship is not cleared for",
+                " interface %s [FAILED!!]",
+                dut,
+                pim_intf,
+            )
+
+    logger.info("[DUT: %s]: PIM neighborship is cleared [PASSED!!]")
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+
+    return True
+
+
+def clear_ip_igmp_interfaces(tgen, dut):
+    """
+    Clear ip igmp interfaces by running
+    "clear ip igmp interfaces" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `dut`: device under test
+
+    Usage
+    -----
+    dut = "r1"
+    result = clear_ip_igmp_interfaces(tgen, dut)
+    Returns
+    -------
+    errormsg(str) or True
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    group_before_clear = {}
+    group_after_clear = {}
+
+    rnode = tgen.routers()[dut]
+
+    logger.info("[DUT: %s]: IGMP group uptime before clear" " igmp groups:", dut)
+    igmp_json = run_frr_cmd(rnode, "show ip igmp groups json", isjson=True)
+
+    total_groups_before_clear = igmp_json["totalGroups"]
+
+    for key, value in igmp_json.items():
+        if type(value) is not dict:
+            continue
+
+        groups = value["groups"]
+        group = groups[0]["group"]
+        uptime = groups[0]["uptime"]
+        group_before_clear[group] = uptime
+
+    logger.info("[DUT: %s]: Clearing ip igmp interfaces", dut)
+    result = run_frr_cmd(rnode, "clear ip igmp interfaces")
+
+    # Waiting for maximum 60 sec
+    for retry in range(1, 13):
+        logger.info(
+            "[DUT: %s]: Waiting for 5 sec for igmp interfaces" " to come up", dut
+        )
+        sleep(5)
+        igmp_json = run_frr_cmd(rnode, "show ip igmp groups json", isjson=True)
+
+        total_groups_after_clear = igmp_json["totalGroups"]
+
+        if total_groups_before_clear == total_groups_after_clear:
+            break
+
+    for key, value in igmp_json.items():
+        if type(value) is not dict:
+            continue
+
+        groups = value["groups"]
+        group = groups[0]["group"]
+        uptime = groups[0]["uptime"]
+        group_after_clear[group] = uptime
+
+    # Verify uptime for groups
+    for group in group_before_clear.keys():
+        d1 = datetime.datetime.strptime(group_before_clear[group], "%H:%M:%S")
+        d2 = datetime.datetime.strptime(group_after_clear[group], "%H:%M:%S")
+        if d2 >= d1:
+            errormsg = ("[DUT: %s]: IGMP group is not cleared", " [FAILED!!]", dut)
+
+    logger.info("[DUT: %s]: IGMP group is cleared [PASSED!!]")
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+
+    return True
+
+
+@retry(attempts=10, wait=2, return_is_str=True)
+def clear_ip_mroute_verify(tgen, dut):
+    """
+    Clear ip mroute by running "clear ip mroute" cli and verify
+    mroutes are up again after mroute clear
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `dut`: Device Under Test
+    Usage
+    -----
+
+    result = clear_ip_mroute_verify(tgen, dut)
+
+    Returns
+    -------
+    errormsg(str) or True
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    mroute_before_clear = {}
+    mroute_after_clear = {}
+
+    rnode = tgen.routers()[dut]
+
+    # sleep(60)
+    logger.info("[DUT: %s]: IP mroutes uptime before clear", dut)
+    mroute_json_1 = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
+
+    for group in mroute_json_1.keys():
+        mroute_before_clear[group] = {}
+        for key in mroute_json_1[group].keys():
+            for _key, _value in mroute_json_1[group][key]["oil"].items():
+                if _key != "pimreg":
+                    mroute_before_clear[group][key] = _value["upTime"]
+
+    logger.info("[DUT: %s]: Clearing ip mroute", dut)
+    result = run_frr_cmd(rnode, "clear ip mroute")
+
+    # RFC 3376: 8.2. Query Interval - Default: 125 seconds
+    # So waiting for maximum 130 sec to get the igmp report
+    for retry in range(1, 26):
+        logger.info("[DUT: %s]: Waiting for 2 sec for mroutes" " to come up", dut)
+        sleep(5)
+        keys_json1 = mroute_json_1.keys()
+        mroute_json_2 = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
+
+        if bool(mroute_json_2):
+            keys_json2 = mroute_json_2.keys()
+
+            for group in mroute_json_2.keys():
+                flag = False
+                for key in mroute_json_2[group].keys():
+                    if "oil" not in mroute_json_2[group]:
+                        continue
+
+                    for _key, _value in mroute_json_2[group][key]["oil"].items():
+                        if _key != "pimreg" and keys_json1 == keys_json2:
+                            break
+                            flag = True
+            if flag:
+                break
+            else:
+                continue
+
+    for group in mroute_json_2.keys():
+        mroute_after_clear[group] = {}
+        for key in mroute_json_2[group].keys():
+            for _key, _value in mroute_json_2[group][key]["oil"].items():
+                if _key != "pimreg":
+                    mroute_after_clear[group][key] = _value["upTime"]
+
+    # Verify uptime for mroute
+    for group in mroute_before_clear.keys():
+        for source in mroute_before_clear[group].keys():
+            if set(mroute_before_clear[group]) != set(mroute_after_clear[group]):
+                errormsg = (
+                    "[DUT: %s]: mroute (%s, %s) has not come"
+                    " up after mroute clear [FAILED!!]" % (dut, source, group)
+                )
+                return errormsg
+
+            d1 = datetime.datetime.strptime(
+                mroute_before_clear[group][source], "%H:%M:%S"
+            )
+            d2 = datetime.datetime.strptime(
+                mroute_after_clear[group][source], "%H:%M:%S"
+            )
+            if d2 >= d1:
+                errormsg = "[DUT: %s]: IP mroute is not cleared" " [FAILED!!]" % (dut)
+
+    logger.info("[DUT: %s]: IP mroute is cleared [PASSED!!]", dut)
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+
+    return True
+
+
+def clear_ip_mroute(tgen, dut=None):
+    """
+    Clear ip mroute by running "clear ip mroute" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `dut`: device under test, default None
+
+    Usage
+    -----
+    clear_ip_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 ip mroute", router)
+        rnode.vtysh_cmd("clear ip mroute")
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+
+
+def reconfig_interfaces(tgen, topo, senderRouter, receiverRouter, packet=None):
+    """
+    Configure interface ip for sender and receiver routers
+    as per bsr packet
+
+    Parameters
+    ----------
+    * `tgen` : Topogen object
+    * `topo` : json file data
+    * `senderRouter` : Sender router
+    * `receiverRouter` : Receiver router
+    * `packet` : BSR packet in raw format
+
+    Returns
+    -------
+    True or False
+    """
+    result = False
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    try:
+        config_data = []
+
+        src_ip = topo["routers"][senderRouter]["bsm"]["bsr_packets"][packet]["src_ip"]
+        dest_ip = topo["routers"][senderRouter]["bsm"]["bsr_packets"][packet]["dest_ip"]
+
+        for destLink, data in topo["routers"][senderRouter]["links"].items():
+            if "type" in data and data["type"] == "loopback":
+                continue
+
+            if "pim" in data and data["pim"] == "enable":
+                sender_interface = data["interface"]
+                sender_interface_ip = data["ipv4"]
+
+                config_data.append("interface {}".format(sender_interface))
+                config_data.append("no ip address {}".format(sender_interface_ip))
+                config_data.append("ip address {}".format(src_ip))
+
+                result = create_common_configuration(
+                    tgen, senderRouter, config_data, "interface_config"
+                )
+                if result is not True:
+                    return False
+
+            config_data = []
+            links = topo["routers"][destLink]["links"]
+            pim_neighbor = {key: links[key] for key in [senderRouter]}
+
+            data = pim_neighbor[senderRouter]
+            if "type" in data and data["type"] == "loopback":
+                continue
+
+            if "pim" in data and data["pim"] == "enable":
+                receiver_interface = data["interface"]
+                receiver_interface_ip = data["ipv4"]
+
+                config_data.append("interface {}".format(receiver_interface))
+                config_data.append("no ip address {}".format(receiver_interface_ip))
+                config_data.append("ip address {}".format(dest_ip))
+
+                result = create_common_configuration(
+                    tgen, receiverRouter, config_data, "interface_config"
+                )
+                if result is not True:
+                    return False
+
+    except InvalidCLIError:
+        # Traceback
+        errormsg = traceback.format_exc()
+        logger.error(errormsg)
+        return errormsg
+
+    logger.debug("Exiting lib API: reconfig_interfaces()")
+    return result
+
+
+def add_rp_interfaces_and_pim_config(tgen, topo, interface, rp, rp_mapping):
+    """
+    Add physical interfaces tp RP for all the RPs
+
+    Parameters
+    ----------
+    * `tgen` : Topogen object
+    * `topo` : json file data
+    * `interface` : RP interface
+    * `rp` : rp for given topology
+    * `rp_mapping` : dictionary of all groups and RPs
+
+    Returns
+    -------
+    True or False
+    """
+    result = False
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    try:
+        config_data = []
+
+        for group, rp_list in rp_mapping.items():
+            for _rp in rp_list:
+                config_data.append("interface {}".format(interface))
+                config_data.append("ip address {}".format(_rp))
+                config_data.append("ip pim")
+
+            result = create_common_configuration(
+                tgen, rp, config_data, "interface_config"
+            )
+            if result is not True:
+                return False
+
+    except InvalidCLIError:
+        # Traceback
+        errormsg = traceback.format_exc()
+        logger.error(errormsg)
+        return errormsg
+
+    logger.debug("Exiting lib API: add_rp_interfaces_and_pim_config()")
+    return result
+
+
+def scapy_send_bsr_raw_packet(
+    tgen, topo, senderRouter, receiverRouter, packet=None, interval=1, count=1
+):
+    """
+    Using scapy Raw() method to send BSR raw packet from one FRR
+    to other
+
+    Parameters:
+    -----------
+    * `tgen` : Topogen object
+    * `topo` : json file data
+    * `senderRouter` : Sender router
+    * `receiverRouter` : Receiver router
+    * `packet` : BSR packet in raw format
+    * `interval` : Interval between the packets
+    * `count` : Number of packets to be sent
+
+    returns:
+    --------
+    errormsg or True
+    """
+
+    global CWD
+    result = ""
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    rnode = tgen.routers()[senderRouter]
+
+    for destLink, data in topo["routers"][senderRouter]["links"].items():
+        if "type" in data and data["type"] == "loopback":
+            continue
+
+        if "pim" in data and data["pim"] == "enable":
+            sender_interface = data["interface"]
+
+        packet = topo["routers"][senderRouter]["bsm"]["bsr_packets"][packet]["data"]
+
+        if interval > 1 or count > 1:
+            cmd = (
+                "nohup /usr/bin/python {}/send_bsr_packet.py '{}' '{}' "
+                "--interval={} --count={} &".format(
+                    CWD, packet, sender_interface, interval, count
+                )
+            )
+        else:
+            cmd = (
+                "/usr/bin/python {}/send_bsr_packet.py '{}' '{}' "
+                "--interval={} --count={}".format(
+                    CWD, packet, sender_interface, interval, count
+                )
+            )
+
+        logger.info("Scapy cmd: \n %s", cmd)
+        result = rnode.run(cmd)
+
+        if result == "":
+            return result
+
+    logger.debug("Exiting lib API: scapy_send_bsr_raw_packet")
+    return True
+
+
+def find_rp_from_bsrp_info(tgen, dut, bsr, grp=None):
+    """
+    Find which RP is having lowest prioriy and returns rp IP
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `dut`: device under test
+    * `bsr`: BSR address
+    * 'grp': Group Address
+
+    Usage
+    -----
+    dut = "r1"
+    result = verify_pim_rp_info(tgen, dut, bsr)
+
+    Returns:
+    dictionary: group and RP, which has to be installed as per
+                lowest priority or highest priority
+    """
+
+    rp_details = {}
+    rnode = tgen.routers()[dut]
+
+    logger.info("[DUT: %s]: Fetching rp details from bsrp-info", dut)
+    bsrp_json = run_frr_cmd(rnode, "show ip pim bsrp-info json", isjson=True)
+
+    if grp not in bsrp_json:
+        return {}
+
+    for group, rp_data in bsrp_json.items():
+        if group == "BSR Address" and bsrp_json["BSR Address"] == bsr:
+            continue
+
+        if group != grp:
+            continue
+
+        rp_priority = {}
+        rp_hash = {}
+
+        for rp, value in rp_data.items():
+            if rp == "Pending RP count":
+                continue
+            rp_priority[value["Rp Address"]] = value["Rp Priority"]
+            rp_hash[value["Rp Address"]] = value["Hash Val"]
+
+        priority_dict = dict(zip(rp_priority.values(), rp_priority.keys()))
+        hash_dict = dict(zip(rp_hash.values(), rp_hash.keys()))
+
+        # RP with lowest priority
+        if len(priority_dict) != 1:
+            rp_p, lowest_priority = sorted(rp_priority.items(), key=lambda x: x[1])[0]
+            rp_details[group] = rp_p
+
+        # RP with highest hash value
+        if len(priority_dict) == 1:
+            rp_h, highest_hash = sorted(rp_hash.items(), key=lambda x: x[1])[-1]
+            rp_details[group] = rp_h
+
+        # RP with highest IP address
+        if len(priority_dict) == 1 and len(hash_dict) == 1:
+            rp_details[group] = sorted(rp_priority.keys())[-1]
+
+    return rp_details
+
+
+@retry(attempts=6, wait=2, return_is_str=True)
+def verify_pim_grp_rp_source(tgen, topo, dut, grp_addr, rp_source, rpadd=None):
+    """
+    Verify pim rp info by running "show ip pim rp-info" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `topo`: JSON file handler
+    * `dut`: device under test
+    * `grp_addr`: IGMP group address
+    * 'rp_source': source from which rp installed
+    * 'rpadd': rp address
+
+    Usage
+    -----
+    dut = "r1"
+    group_address = "225.1.1.1"
+    rp_source = "BSR"
+    result = verify_pim_rp_and_source(tgen, topo, dut, group_address, rp_source)
+
+    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 ip rp info", dut)
+    show_ip_rp_info_json = run_frr_cmd(rnode, "show ip pim rp-info json", isjson=True)
+
+    if rpadd != None:
+        rp_json = show_ip_rp_info_json[rpadd]
+        if rp_json[0]["group"] == grp_addr:
+            if rp_json[0]["source"] == rp_source:
+                logger.info(
+                    "[DUT %s]: Verifying Group and rp_source [PASSED]"
+                    "Found Expected: %s, %s"
+                    % (dut, rp_json[0]["group"], rp_json[0]["source"])
+                )
+                return True
+            else:
+                errormsg = (
+                    "[DUT %s]: Verifying Group and rp_source [FAILED]"
+                    "Expected (%s, %s) "
+                    "Found (%s, %s)"
+                    % (
+                        dut,
+                        grp_addr,
+                        rp_source,
+                        rp_json[0]["group"],
+                        rp_json[0]["source"],
+                    )
+                )
+                return errormsg
+        errormsg = (
+            "[DUT %s]: Verifying Group and rp_source [FAILED]"
+            "Expected: %s, %s but not found" % (dut, grp_addr, rp_source)
+        )
+        return errormsg
+
+    for rp in show_ip_rp_info_json:
+        rp_json = show_ip_rp_info_json[rp]
+        logger.info("%s", rp_json)
+        if rp_json[0]["group"] == grp_addr:
+            if rp_json[0]["source"] == rp_source:
+                logger.info(
+                    "[DUT %s]: Verifying Group and rp_source [PASSED]"
+                    "Found Expected: %s, %s"
+                    % (dut, rp_json[0]["group"], rp_json[0]["source"])
+                )
+                return True
+            else:
+                errormsg = (
+                    "[DUT %s]: Verifying Group and rp_source [FAILED]"
+                    "Expected (%s, %s) "
+                    "Found (%s, %s)"
+                    % (
+                        dut,
+                        grp_addr,
+                        rp_source,
+                        rp_json[0]["group"],
+                        rp_json[0]["source"],
+                    )
+                )
+                return errormsg
+
+    errormsg = (
+        "[DUT %s]: Verifying Group and rp_source [FAILED]"
+        "Expected: %s, %s but not found" % (dut, grp_addr, rp_source)
+    )
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+
+    return errormsg
+
+
+@retry(attempts=31, wait=2, return_is_str=True)
+def verify_pim_bsr(tgen, topo, dut, bsr_ip):
+    """
+    Verify all PIM interface are up and running, config is verified
+    using "show ip pim interface" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `topo` : json file data
+    * `dut` : device under test
+    * 'bsr' : bsr ip to be verified
+
+    Usage
+    -----
+    result = verify_pim_bsr(tgen, topo, dut, bsr_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 PIM bsr status:", dut)
+
+        rnode = tgen.routers()[dut]
+        pim_bsr_json = rnode.vtysh_cmd("show ip pim bsr json", isjson=True)
+
+        logger.info("show_ip_pim_bsr_json: \n %s", pim_bsr_json)
+
+        # Verifying PIM bsr
+        if pim_bsr_json["bsr"] != bsr_ip:
+            errormsg = (
+                "[DUT %s]:"
+                "bsr status: not found"
+                "[FAILED]!! Expected : %s, Found : %s"
+                % (dut, bsr_ip, pim_bsr_json["bsr"])
+            )
+            return errormsg
+
+        logger.info(
+            "[DUT %s]:" " bsr status: found, Address :%s" " [PASSED]!!",
+            dut,
+            pim_bsr_json["bsr"],
+        )
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True
+
+
+@retry(attempts=31, wait=2, return_is_str=True)
+def verify_ip_pim_upstream_rpf(tgen, topo, dut, interface, group_addresses, rp=None):
+    """
+    Verify IP PIM upstream rpf, config is verified
+    using "show ip pim neighbor" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `topo` : json file data
+    * `dut` : devuce under test
+    * `interface` : upstream interface
+    * `group_addresses` : list of group address for which upstream info
+                          needs to be checked
+    * `rp` : RP address
+
+    Usage
+    -----
+    result = verify_ip_pim_upstream_rpf(gen, topo, dut, interface,
+                                        group_addresses, rp=None)
+
+    Returns
+    -------
+    errormsg(str) or True
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    if "pim" in topo["routers"][dut]:
+
+        logger.info("[DUT: %s]: Verifying ip pim upstream rpf:", dut)
+
+        rnode = tgen.routers()[dut]
+        show_ip_pim_upstream_rpf_json = rnode.vtysh_cmd(
+            "show ip pim upstream-rpf json", isjson=True
+        )
+
+        logger.info(
+            "show_ip_pim_upstream_rpf_json: \n %s", show_ip_pim_upstream_rpf_json
+        )
+
+        if type(group_addresses) is not list:
+            group_addresses = [group_addresses]
+
+        for grp_addr in group_addresses:
+            for destLink, data in topo["routers"][dut]["links"].items():
+                if "type" in data and data["type"] == "loopback":
+                    continue
+
+                if "pim" not in topo["routers"][destLink]:
+                    continue
+
+                # Verify RP info
+                if rp is None:
+                    rp_details = find_rp_details(tgen, topo)
+                else:
+                    rp_details = {dut: ip}
+                    rp_details[dut] = rp
+
+                if dut in rp_details:
+                    pim_nh_intf_ip = topo["routers"][dut]["links"]["lo"]["ipv4"].split(
+                        "/"
+                    )[0]
+                else:
+                    if destLink not in interface:
+                        continue
+
+                    links = topo["routers"][destLink]["links"]
+                    pim_neighbor = {key: links[key] for key in [dut]}
+
+                    data = pim_neighbor[dut]
+                    if "pim" in data and data["pim"] == "enable":
+                        pim_nh_intf_ip = data["ipv4"].split("/")[0]
+
+                upstream_rpf_json = show_ip_pim_upstream_rpf_json[grp_addr]["*"]
+
+                # Verifying ip pim upstream rpf
+                if (
+                    upstream_rpf_json["rpfInterface"] == interface
+                    and upstream_rpf_json["ribNexthop"] != pim_nh_intf_ip
+                ):
+                    errormsg = (
+                        "[DUT %s]: Verifying group: %s, "
+                        "rpf interface: %s, "
+                        " rib Nexthop check [FAILED]!!"
+                        "Expected: %s, Found: %s"
+                        % (
+                            dut,
+                            grp_addr,
+                            interface,
+                            pim_nh_intf_ip,
+                            upstream_rpf_json["ribNexthop"],
+                        )
+                    )
+                    return errormsg
+
+                logger.info(
+                    "[DUT %s]: Verifying group: %s,"
+                    " rpf interface: %s, "
+                    " rib Nexthop: %s [PASSED]!!",
+                    dut,
+                    grp_addr,
+                    interface,
+                    pim_nh_intf_ip,
+                )
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True
+
+
+def enable_disable_pim_unicast_bsm(tgen, router, intf, enable=True):
+    """
+    Helper API to enable or disable pim bsm on interfaces
+
+    Parameters
+    ----------
+    * `tgen` : Topogen object
+    * `router` : router id to be configured.
+    * `intf` : Interface to be configured
+    * `enable` : this flag denotes if config should be enabled or disabled
+
+    Returns
+    -------
+    True or False
+    """
+    result = False
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    try:
+        config_data = []
+        cmd = "interface {}".format(intf)
+        config_data.append(cmd)
+
+        if enable == True:
+            config_data.append("ip pim unicast-bsm")
+        else:
+            config_data.append("no ip pim unicast-bsm")
+
+        result = create_common_configuration(
+            tgen, router, config_data, "interface_config", build=False
+        )
+        if result is not True:
+            return False
+
+    except InvalidCLIError:
+        # Traceback
+        errormsg = traceback.format_exc()
+        logger.error(errormsg)
+        return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return result
+
+
+def enable_disable_pim_bsm(tgen, router, intf, enable=True):
+    """
+    Helper API to enable or disable pim bsm on interfaces
+
+    Parameters
+    ----------
+    * `tgen` : Topogen object
+    * `router` : router id to be configured.
+    * `intf` : Interface to be configured
+    * `enable` : this flag denotes if config should be enabled or disabled
+
+    Returns
+    -------
+    True or False
+    """
+    result = False
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    try:
+        config_data = []
+        cmd = "interface {}".format(intf)
+        config_data.append(cmd)
+
+        if enable is True:
+            config_data.append("ip pim bsm")
+        else:
+            config_data.append("no ip pim bsm")
+
+        result = create_common_configuration(
+            tgen, router, config_data, "interface_config", build=False
+        )
+        if result is not True:
+            return False
+
+    except InvalidCLIError:
+        # Traceback
+        errormsg = traceback.format_exc()
+        logger.error(errormsg)
+        return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return result
+
+
+@retry(attempts=31, wait=2, return_is_str=True)
+def verify_ip_pim_join(tgen, topo, dut, interface, group_addresses, src_address=None):
+    """
+    Verify ip pim join by running "show ip pim join" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `topo`: JSON file handler
+    * `dut`: device under test
+    * `interface`: interface name, from which PIM join would come
+    * `group_addresses`: IGMP group address
+    * `src_address`: Source address
+
+    Usage
+    -----
+    dut = "r1"
+    interface = "r1-r0-eth0"
+    group_address = "225.1.1.1"
+    result = verify_ip_pim_join(tgen, dut, star, group_address, interface)
+
+    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 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_addr in group_addresses:
+        # Verify if IGMP is enabled in DUT
+        if "igmp" not in topo["routers"][dut]:
+            pim_join = True
+        else:
+            pim_join = False
+
+        interface_json = show_pim_join_json[interface]
+
+        grp_addr = grp_addr.split("/")[0]
+        for source, data in interface_json[grp_addr].items():
+
+            # Verify pim join
+            if pim_join:
+                if data["group"] == grp_addr and data["channelJoinName"] == "JOIN":
+                    logger.info(
+                        "[DUT %s]: Verifying pim join for group: %s"
+                        "[PASSED]!!  Found Expected: (%s)",
+                        dut,
+                        grp_addr,
+                        data["channelJoinName"],
+                    )
+                else:
+                    errormsg = (
+                        "[DUT %s]: Verifying pim join for group: %s"
+                        "[FAILED]!! Expected: (%s) "
+                        "Found: (%s)" % (dut, grp_addr, "JOIN", data["channelJoinName"])
+                    )
+                    return errormsg
+
+            if not pim_join:
+                if data["group"] == grp_addr and data["channelJoinName"] == "NOINFO":
+                    logger.info(
+                        "[DUT %s]: Verifying pim join for group: %s"
+                        "[PASSED]!!  Found Expected: (%s)",
+                        dut,
+                        grp_addr,
+                        data["channelJoinName"],
+                    )
+                else:
+                    errormsg = (
+                        "[DUT %s]: Verifying pim join for group: %s"
+                        "[FAILED]!! Expected: (%s) "
+                        "Found: (%s)"
+                        % (dut, grp_addr, "NOINFO", data["channelJoinName"])
+                    )
+                    return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True
+
+
+@retry(attempts=31, wait=2, return_is_dict=True)
+def verify_igmp_config(tgen, input_dict, stats_return=False):
+    """
+    Verify igmp 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
+
+    Usage
+    -----
+    input_dict ={
+        "l1": {
+            "igmp": {
+                "interfaces": {
+                    "l1-i1-eth1": {
+                        "igmp": {
+                            "query": {
+                                "query-interval" : 200,
+                                "query-max-response-time" : 100
+                            },
+                            "statistics": {
+                                "queryV2" : 2,
+                                "reportV2" : 1
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    result = verify_igmp_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 ip igmp statistics"
+            else:
+                cmd = "show ip igmp"
+
+            logger.info(
+                "[DUT: %s]: Verifying IGMP interface %s detail:", dut, interface
+            )
+
+            if statistics:
+                if (
+                    "report"
+                    in input_dict[dut]["igmp"]["interfaces"][interface]["igmp"][
+                        "statistics"
+                    ]
+                ):
+                    report = True
+
+            if statistics and report:
+                show_ip_igmp_intf_json = run_frr_cmd(
+                    rnode, "{} json".format(cmd, interface), isjson=True
+                )
+                intf_detail_json = show_ip_igmp_intf_json["global"]
+            else:
+                show_ip_igmp_intf_json = run_frr_cmd(
+                    rnode, "{} interface {} json".format(cmd, interface), isjson=True
+                )
+
+            if not report:
+                if interface not in show_ip_igmp_intf_json:
+                    errormsg = (
+                        "[DUT %s]: IGMP interface: %s "
+                        " is not present in CLI output "
+                        "[FAILED]!! " % (dut, interface)
+                    )
+                    return errormsg
+
+                else:
+                    intf_detail_json = show_ip_igmp_intf_json[interface]
+
+            if stats_return:
+                igmp_stats = {}
+
+            if "statistics" in data["igmp"]:
+                if stats_return:
+                    igmp_stats["statistics"] = {}
+                for query, value in data["igmp"]["statistics"].items():
+                    if query == "queryV2":
+                        # Verifying IGMP interface queryV2 statistics
+                        if stats_return:
+                            igmp_stats["statistics"][query] = intf_detail_json[
+                                "queryV2"
+                            ]
+
+                        else:
+                            if intf_detail_json["queryV2"] != value:
+                                errormsg = (
+                                    "[DUT %s]: IGMP interface: %s "
+                                    " queryV2 statistics verification "
+                                    "[FAILED]!! Expected : %s,"
+                                    " Found : %s"
+                                    % (
+                                        dut,
+                                        interface,
+                                        value,
+                                        intf_detail_json["queryV2"],
+                                    )
+                                )
+                                return errormsg
+
+                            logger.info(
+                                "[DUT %s]: IGMP interface: %s "
+                                "queryV2 statistics is %s",
+                                dut,
+                                interface,
+                                value,
+                            )
+
+                    if query == "reportV2":
+                        # Verifying IGMP interface timerV2 statistics
+                        if stats_return:
+                            igmp_stats["statistics"][query] = intf_detail_json[
+                                "reportV2"
+                            ]
+
+                        else:
+                            if intf_detail_json["reportV2"] <= value:
+                                errormsg = (
+                                    "[DUT %s]: IGMP reportV2 "
+                                    "statistics verification "
+                                    "[FAILED]!! Expected : %s "
+                                    "or more, Found : %s"
+                                    % (
+                                        dut,
+                                        interface,
+                                        value,
+                                        intf_detail_json["reportV2"],
+                                    )
+                                )
+                                return errormsg
+
+                            logger.info(
+                                "[DUT %s]: IGMP reportV2 " "statistics is %s",
+                                dut,
+                                intf_detail_json["reportV2"],
+                            )
+
+            if "query" in data["igmp"]:
+                for query, value in data["igmp"]["query"].items():
+                    if query == "query-interval":
+                        # Verifying IGMP interface query interval timer
+                        if intf_detail_json["timerQueryInterval"] != value:
+                            errormsg = (
+                                "[DUT %s]: IGMP interface: %s "
+                                " query-interval verification "
+                                "[FAILED]!! Expected : %s,"
+                                " Found : %s"
+                                % (
+                                    dut,
+                                    interface,
+                                    value,
+                                    intf_detail_json["timerQueryInterval"],
+                                )
+                            )
+                            return errormsg
+
+                        logger.info(
+                            "[DUT %s]: IGMP 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]: IGMP 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]: IGMP 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]: IGMP 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]: IGMP 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]: IGMP 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]: IGMP interface: %s "
+                            "last-member-query-interval is %s ms",
+                            dut,
+                            interface,
+                            value * intf_detail_json["lastMemberQueryCount"] * 100,
+                        )
+
+            if "version" in data["igmp"]:
+                # Verifying IGMP interface state is up
+                if intf_detail_json["state"] != "up":
+                    errormsg = (
+                        "[DUT %s]: IGMP interface: %s "
+                        " state: %s verification "
+                        "[FAILED]!!" % (dut, interface, intf_detail_json["state"])
+                    )
+                    return errormsg
+
+                logger.info(
+                    "[DUT %s]: IGMP 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 igmp_stats
+
+
+@retry(attempts=31, wait=2, return_is_str=True)
+def verify_pim_config(tgen, input_dict):
+    """
+    Verify pim interface details, verifying following configs:
+    drPriority
+    helloPeriod
+    helloReceived
+    helloSend
+    drAddress
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `input_dict` : Input dict data, required to verify
+                     timer
+
+    Usage
+    -----
+    input_dict ={
+        "l1": {
+            "igmp": {
+                "interfaces": {
+                    "l1-i1-eth1": {
+                        "pim": {
+                                "drPriority" : 10,
+                                "helloPeriod" : 5
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    result = verify_pim_config(tgen, input_dict)
+
+    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]["pim"]["interfaces"].items():
+
+            logger.info("[DUT: %s]: Verifying PIM interface %s detail:", dut, interface)
+
+            show_ip_igmp_intf_json = run_frr_cmd(
+                rnode, "show ip pim interface {} json".format(interface), isjson=True
+            )
+
+            if interface not in show_ip_igmp_intf_json:
+                errormsg = (
+                    "[DUT %s]: PIM interface: %s "
+                    " is not present in CLI output "
+                    "[FAILED]!! " % (dut, interface)
+                )
+                return errormsg
+
+            intf_detail_json = show_ip_igmp_intf_json[interface]
+
+            for config, value in data.items():
+                if config == "helloPeriod":
+                    # Verifying PIM interface helloPeriod
+                    if intf_detail_json["helloPeriod"] != value:
+                        errormsg = (
+                            "[DUT %s]: PIM interface: %s "
+                            " helloPeriod verification "
+                            "[FAILED]!! Expected : %s,"
+                            " Found : %s"
+                            % (dut, interface, value, intf_detail_json["helloPeriod"])
+                        )
+                        return errormsg
+
+                    logger.info(
+                        "[DUT %s]: PIM interface: %s " "helloPeriod is %s",
+                        dut,
+                        interface,
+                        value,
+                    )
+
+                if config == "drPriority":
+                    # Verifying PIM interface drPriority
+                    if intf_detail_json["drPriority"] != value:
+                        errormsg = (
+                            "[DUT %s]: PIM interface: %s "
+                            " drPriority verification "
+                            "[FAILED]!! Expected : %s,"
+                            " Found : %s"
+                            % (dut, interface, value, intf_detail_json["drPriority"])
+                        )
+                        return errormsg
+
+                    logger.info(
+                        "[DUT %s]: PIM interface: %s " "drPriority is %s",
+                        dut,
+                        interface,
+                        value,
+                    )
+
+                if config == "drAddress":
+                    # Verifying PIM interface drAddress
+                    if intf_detail_json["drAddress"] != value:
+                        errormsg = (
+                            "[DUT %s]: PIM interface: %s "
+                            " drAddress verification "
+                            "[FAILED]!! Expected : %s,"
+                            " Found : %s"
+                            % (dut, interface, value, intf_detail_json["drAddress"])
+                        )
+                        return errormsg
+
+                    logger.info(
+                        "[DUT %s]: PIM interface: %s " "drAddress is %s",
+                        dut,
+                        interface,
+                        value,
+                    )
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True
+
+
+@retry(attempts=21, wait=2, return_is_dict=True)
+def verify_multicast_traffic(tgen, input_dict, return_traffic=False):
+    """
+    Verify multicast traffic by running
+    "show multicast traffic count json" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `input_dict(dict)`: defines DUT, what and for which interfaces
+                          traffic needs to be verified
+    * `return_traffic`: returns traffic stats
+    Usage
+    -----
+    input_dict = {
+        "r1": {
+            "traffic_received": ["r1-r0-eth0"],
+            "traffic_sent": ["r1-r0-eth0"]
+        }
+    }
+
+    result = verify_multicast_traffic(tgen, input_dict)
+
+    Returns
+    -------
+    errormsg(str) or True
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    traffic_dict = {}
+    for dut in input_dict.keys():
+        if dut not in tgen.routers():
+            continue
+
+        rnode = tgen.routers()[dut]
+
+        logger.info("[DUT: %s]: Verifying multicast " "traffic", dut)
+
+        show_multicast_traffic_json = run_frr_cmd(
+            rnode, "show ip multicast count json", isjson=True
+        )
+
+        for traffic_type, interfaces in input_dict[dut].items():
+            traffic_dict[traffic_type] = {}
+            if traffic_type == "traffic_received":
+                for interface in interfaces:
+                    traffic_dict[traffic_type][interface] = {}
+                    interface_json = show_multicast_traffic_json[interface]
+
+                    if interface_json["pktsIn"] == 0 and interface_json["bytesIn"] == 0:
+                        errormsg = (
+                            "[DUT %s]: Multicast traffic is "
+                            "not received on interface %s "
+                            "PktsIn: %s, BytesIn: %s "
+                            "[FAILED]!!"
+                            % (
+                                dut,
+                                interface,
+                                interface_json["pktsIn"],
+                                interface_json["bytesIn"],
+                            )
+                        )
+                        return errormsg
+
+                    elif (
+                        interface_json["pktsIn"] != 0 and interface_json["bytesIn"] != 0
+                    ):
+
+                        traffic_dict[traffic_type][interface][
+                            "pktsIn"
+                        ] = interface_json["pktsIn"]
+                        traffic_dict[traffic_type][interface][
+                            "bytesIn"
+                        ] = interface_json["bytesIn"]
+
+                        logger.info(
+                            "[DUT %s]: Multicast traffic is "
+                            "received on interface %s "
+                            "PktsIn: %s, BytesIn: %s "
+                            "[PASSED]!!"
+                            % (
+                                dut,
+                                interface,
+                                interface_json["pktsIn"],
+                                interface_json["bytesIn"],
+                            )
+                        )
+
+                    else:
+                        errormsg = (
+                            "[DUT %s]: Multicast traffic interface %s:"
+                            " Miss-match in "
+                            "PktsIn: %s, BytesIn: %s"
+                            "[FAILED]!!"
+                            % (
+                                dut,
+                                interface,
+                                interface_json["pktsIn"],
+                                interface_json["bytesIn"],
+                            )
+                        )
+                        return errormsg
+
+            if traffic_type == "traffic_sent":
+                traffic_dict[traffic_type] = {}
+                for interface in interfaces:
+                    traffic_dict[traffic_type][interface] = {}
+                    interface_json = show_multicast_traffic_json[interface]
+
+                    if (
+                        interface_json["pktsOut"] == 0
+                        and interface_json["bytesOut"] == 0
+                    ):
+                        errormsg = (
+                            "[DUT %s]: Multicast traffic is "
+                            "not received on interface %s "
+                            "PktsIn: %s, BytesIn: %s"
+                            "[FAILED]!!"
+                            % (
+                                dut,
+                                interface,
+                                interface_json["pktsOut"],
+                                interface_json["bytesOut"],
+                            )
+                        )
+                        return errormsg
+
+                    elif (
+                        interface_json["pktsOut"] != 0
+                        and interface_json["bytesOut"] != 0
+                    ):
+
+                        traffic_dict[traffic_type][interface][
+                            "pktsOut"
+                        ] = interface_json["pktsOut"]
+                        traffic_dict[traffic_type][interface][
+                            "bytesOut"
+                        ] = interface_json["bytesOut"]
+
+                        logger.info(
+                            "[DUT %s]: Multicast traffic is "
+                            "received on interface %s "
+                            "PktsOut: %s, BytesOut: %s "
+                            "[PASSED]!!"
+                            % (
+                                dut,
+                                interface,
+                                interface_json["pktsOut"],
+                                interface_json["bytesOut"],
+                            )
+                        )
+                    else:
+                        errormsg = (
+                            "[DUT %s]: Multicast traffic interface %s:"
+                            " Miss-match in "
+                            "PktsOut: %s, BytesOut: %s "
+                            "[FAILED]!!"
+                            % (
+                                dut,
+                                interface,
+                                interface_json["pktsOut"],
+                                interface_json["bytesOut"],
+                            )
+                        )
+                        return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True if return_traffic == False else traffic_dict
+
+
+def get_refCount_for_mroute(tgen, dut, iif, src_address, group_addresses):
+    """
+    Verify upstream inbound interface  is updated correctly
+    by running "show ip pim upstream" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `dut`: device under test
+    * `iif`: inbound interface
+    * `src_address`: source address
+    * `group_addresses`: IGMP group address
+
+    Usage
+    -----
+    dut = "r1"
+    iif = "r1-r0-eth0"
+    src_address = "*"
+    group_address = "225.1.1.1"
+    result = get_refCount_for_mroute(tgen, dut, iif, src_address,
+                                    group_address)
+
+    Returns
+    -------
+    refCount(int)
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    refCount = 0
+    if dut not in tgen.routers():
+        return False
+
+    rnode = tgen.routers()[dut]
+
+    logger.info("[DUT: %s]: Verifying refCount for mroutes: ", dut)
+    show_ip_pim_upstream_json = run_frr_cmd(
+        rnode, "show ip pim upstream json", isjson=True
+    )
+
+    if type(group_addresses) is not list:
+        group_addresses = [group_addresses]
+
+    for grp_addr in group_addresses:
+        # Verify group address
+        if grp_addr not in show_ip_pim_upstream_json:
+            errormsg = "[DUT %s]: Verifying upstream" " for group %s [FAILED]!!" % (
+                dut,
+                grp_addr,
+            )
+            return errormsg
+        group_addr_json = show_ip_pim_upstream_json[grp_addr]
+
+        # Verify source address
+        if src_address not in group_addr_json:
+            errormsg = "[DUT %s]: Verifying upstream" " for (%s,%s) [FAILED]!!" % (
+                dut,
+                src_address,
+                grp_addr,
+            )
+            return errormsg
+
+        # Verify Inbound Interface
+        if group_addr_json[src_address]["inboundInterface"] == iif:
+            refCount = group_addr_json[src_address]["refCount"]
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return refCount
+
+
+@retry(attempts=21, wait=2, return_is_str=True)
+def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag):
+    """
+    Verify flag state for mroutes and make sure (*, G)/(S, G) are having
+    coorect flags by running "show ip mroute" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `dut`: device under test
+    * `src_address`: source address
+    * `group_addresses`: IGMP group address
+    * `flag`: flag state, needs to be verified
+
+    Usage
+    -----
+    dut = "r1"
+    flag = "SC"
+    group_address = "225.1.1.1"
+    result = verify_multicast_flag_state(tgen, dut, src_address,
+                                        group_address, flag)
+
+    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 flag state for mroutes", dut)
+    show_ip_mroute_json = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
+
+    if bool(show_ip_mroute_json) == False:
+        error_msg = "[DUT %s]: mroutes are not present or flushed out !!" % (dut)
+        return error_msg
+
+    if type(group_addresses) is not list:
+        group_addresses = [group_addresses]
+
+    for grp_addr in group_addresses:
+        if grp_addr not in show_ip_mroute_json:
+            errormsg = (
+                "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! ",
+                dut,
+                src_address,
+                grp_addr,
+            )
+            return errormsg
+        else:
+            group_addr_json = show_ip_mroute_json[grp_addr]
+
+        if src_address not in group_addr_json:
+            errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
+                dut,
+                src_address,
+                grp_addr,
+            )
+            return errormsg
+        else:
+            mroutes = group_addr_json[src_address]
+
+        if mroutes["installed"] != 0:
+            logger.info(
+                "[DUT %s]: mroute (%s,%s) is installed", dut, src_address, grp_addr
+            )
+
+            if mroutes["flags"] != flag:
+                errormsg = (
+                    "[DUT %s]: Verifying flag for (%s, %s) "
+                    "mroute [FAILED]!! "
+                    "Expected: %s Found: %s"
+                    % (dut, src_address, grp_addr, flag, mroutes["flags"])
+                )
+                return errormsg
+
+            logger.info(
+                "[DUT %s]: Verifying flag for (%s, %s)"
+                " mroute, [PASSED]!!  "
+                "Found Expected: %s",
+                dut,
+                src_address,
+                grp_addr,
+                mroutes["flags"],
+            )
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True
index b85e193d3bc08cd1c38b346bfdb169e39d4ec98e..7b3c8593ccb9a9177f0e80178b6dc84f6616f699 100755 (executable)
@@ -107,16 +107,25 @@ def test_json_intersect_multilevel_true():
     dcomplete = {
         "i1": "item1",
         "i2": "item2",
-        "i3": {"i100": "item100",},
+        "i3": {
+            "i100": "item100",
+        },
         "i4": {
-            "i41": {"i411": "item411",},
-            "i42": {"i421": "item421", "i422": "item422",},
+            "i41": {
+                "i411": "item411",
+            },
+            "i42": {
+                "i421": "item421",
+                "i422": "item422",
+            },
         },
     }
 
     dsub1 = {
         "i1": "item1",
-        "i3": {"i100": "item100",},
+        "i3": {
+            "i100": "item100",
+        },
         "i10": None,
     }
     dsub2 = {
@@ -126,10 +135,36 @@ def test_json_intersect_multilevel_true():
     }
     dsub3 = {
         "i2": "item2",
-        "i4": {"i41": {"i411": "item411",}, "i42": {"i422": "item422", "i450": None,}},
+        "i4": {
+            "i41": {
+                "i411": "item411",
+            },
+            "i42": {
+                "i422": "item422",
+                "i450": None,
+            },
+        },
+    }
+    dsub4 = {
+        "i2": "item2",
+        "i4": {
+            "i41": {},
+            "i42": {
+                "i450": None,
+            },
+        },
+    }
+    dsub5 = {
+        "i2": "item2",
+        "i3": {
+            "i100": "item100",
+        },
+        "i4": {
+            "i42": {
+                "i450": None,
+            }
+        },
     }
-    dsub4 = {"i2": "item2", "i4": {"i41": {}, "i42": {"i450": None,}}}
-    dsub5 = {"i2": "item2", "i3": {"i100": "item100",}, "i4": {"i42": {"i450": None,}}}
 
     assert json_cmp(dcomplete, dsub1) is None
     assert json_cmp(dcomplete, dsub2) is None
@@ -144,17 +179,26 @@ def test_json_intersect_multilevel_false():
     dcomplete = {
         "i1": "item1",
         "i2": "item2",
-        "i3": {"i100": "item100",},
+        "i3": {
+            "i100": "item100",
+        },
         "i4": {
-            "i41": {"i411": "item411",},
-            "i42": {"i421": "item421", "i422": "item422",},
+            "i41": {
+                "i411": "item411",
+            },
+            "i42": {
+                "i421": "item421",
+                "i422": "item422",
+            },
         },
     }
 
     # Incorrect sub-level value
     dsub1 = {
         "i1": "item1",
-        "i3": {"i100": "item00",},
+        "i3": {
+            "i100": "item00",
+        },
         "i10": None,
     }
     # Inexistent sub-level
@@ -166,14 +210,41 @@ def test_json_intersect_multilevel_false():
     # Inexistent sub-level value
     dsub3 = {
         "i1": "item1",
-        "i3": {"i100": None,},
+        "i3": {
+            "i100": None,
+        },
     }
     # Inexistent sub-sub-level value
-    dsub4 = {"i4": {"i41": {"i412": "item412",}, "i42": {"i421": "item421",}}}
+    dsub4 = {
+        "i4": {
+            "i41": {
+                "i412": "item412",
+            },
+            "i42": {
+                "i421": "item421",
+            },
+        }
+    }
     # Invalid sub-sub-level value
-    dsub5 = {"i4": {"i41": {"i411": "item411",}, "i42": {"i421": "item420000",}}}
+    dsub5 = {
+        "i4": {
+            "i41": {
+                "i411": "item411",
+            },
+            "i42": {
+                "i421": "item420000",
+            },
+        }
+    }
     # sub-sub-level should be value
-    dsub6 = {"i4": {"i41": {"i411": "item411",}, "i42": "foobar",}}
+    dsub6 = {
+        "i4": {
+            "i41": {
+                "i411": "item411",
+            },
+            "i42": "foobar",
+        }
+    }
 
     assert json_cmp(dcomplete, dsub1) is not None
     assert json_cmp(dcomplete, dsub2) is not None
@@ -187,7 +258,15 @@ def test_json_with_list_sucess():
     "Test successful json comparisons that have lists."
 
     dcomplete = {
-        "list": [{"i1": "item 1", "i2": "item 2",}, {"i10": "item 10",},],
+        "list": [
+            {
+                "i1": "item 1",
+                "i2": "item 2",
+            },
+            {
+                "i10": "item 10",
+            },
+        ],
         "i100": "item 100",
     }
 
@@ -197,12 +276,19 @@ def test_json_with_list_sucess():
     }
     # Test list correct list items
     dsub2 = {
-        "list": [{"i1": "item 1",},],
+        "list": [
+            {
+                "i1": "item 1",
+            },
+        ],
         "i100": "item 100",
     }
     # Test list correct list size
     dsub3 = {
-        "list": [{}, {},],
+        "list": [
+            {},
+            {},
+        ],
     }
 
     assert json_cmp(dcomplete, dsub1) is None
@@ -214,7 +300,15 @@ def test_json_with_list_failure():
     "Test failed json comparisons that have lists."
 
     dcomplete = {
-        "list": [{"i1": "item 1", "i2": "item 2",}, {"i10": "item 10",},],
+        "list": [
+            {
+                "i1": "item 1",
+                "i2": "item 2",
+            },
+            {
+                "i10": "item 10",
+            },
+        ],
         "i100": "item 100",
     }
 
@@ -224,12 +318,20 @@ def test_json_with_list_failure():
     }
     # Test list incorrect list items
     dsub2 = {
-        "list": [{"i1": "item 2",},],
+        "list": [
+            {
+                "i1": "item 2",
+            },
+        ],
         "i100": "item 100",
     }
     # Test list correct list size
     dsub3 = {
-        "list": [{}, {}, {},],
+        "list": [
+            {},
+            {},
+            {},
+        ],
     }
 
     assert json_cmp(dcomplete, dsub1) is not None
@@ -241,20 +343,52 @@ def test_json_list_start_success():
     "Test JSON encoded data that starts with a list that should succeed."
 
     dcomplete = [
-        {"id": 100, "value": "abc",},
-        {"id": 200, "value": "abcd",},
-        {"id": 300, "value": "abcde",},
+        {
+            "id": 100,
+            "value": "abc",
+        },
+        {
+            "id": 200,
+            "value": "abcd",
+        },
+        {
+            "id": 300,
+            "value": "abcde",
+        },
     ]
 
-    dsub1 = [{"id": 100, "value": "abc",}]
+    dsub1 = [
+        {
+            "id": 100,
+            "value": "abc",
+        }
+    ]
 
-    dsub2 = [{"id": 100, "value": "abc",}, {"id": 200, "value": "abcd",}]
+    dsub2 = [
+        {
+            "id": 100,
+            "value": "abc",
+        },
+        {
+            "id": 200,
+            "value": "abcd",
+        },
+    ]
 
-    dsub3 = [{"id": 300, "value": "abcde",}]
+    dsub3 = [
+        {
+            "id": 300,
+            "value": "abcde",
+        }
+    ]
 
     dsub4 = []
 
-    dsub5 = [{"id": 100,}]
+    dsub5 = [
+        {
+            "id": 100,
+        }
+    ]
 
     assert json_cmp(dcomplete, dsub1) is None
     assert json_cmp(dcomplete, dsub2) is None
@@ -272,13 +406,44 @@ def test_json_list_start_failure():
         {"id": 300, "value": "abcde"},
     ]
 
-    dsub1 = [{"id": 100, "value": "abcd",}]
+    dsub1 = [
+        {
+            "id": 100,
+            "value": "abcd",
+        }
+    ]
 
-    dsub2 = [{"id": 100, "value": "abc",}, {"id": 200, "value": "abc",}]
+    dsub2 = [
+        {
+            "id": 100,
+            "value": "abc",
+        },
+        {
+            "id": 200,
+            "value": "abc",
+        },
+    ]
 
-    dsub3 = [{"id": 100, "value": "abc",}, {"id": 350, "value": "abcde",}]
+    dsub3 = [
+        {
+            "id": 100,
+            "value": "abc",
+        },
+        {
+            "id": 350,
+            "value": "abcde",
+        },
+    ]
 
-    dsub4 = [{"value": "abcx",}, {"id": 300, "value": "abcde",}]
+    dsub4 = [
+        {
+            "value": "abcx",
+        },
+        {
+            "id": 300,
+            "value": "abcde",
+        },
+    ]
 
     assert json_cmp(dcomplete, dsub1) is not None
     assert json_cmp(dcomplete, dsub2) is not None
index 3e92bd7565249e5190aa3ac63d6b4853f07a2bcc..7c52e824c198d3a4ed2f3c070256ad9a5fe63dd6 100644 (file)
@@ -336,7 +336,9 @@ class Topogen(object):
         for gear in self.gears.values():
             errors += gear.stop()
         if len(errors) > 0:
-            assert "Errors found post shutdown - details follow:" == 0, errors
+            logger.error(
+                "Errors found post shutdown - details follow: {}".format(errors)
+            )
 
         self.net.stop()
 
@@ -552,6 +554,7 @@ class TopoRouter(TopoGear):
     RD_SHARP = 14
     RD_BABEL = 15
     RD_PBRD = 16
+    RD_PATH = 17
     RD = {
         RD_ZEBRA: "zebra",
         RD_RIP: "ripd",
@@ -569,6 +572,7 @@ class TopoRouter(TopoGear):
         RD_SHARP: "sharpd",
         RD_BABEL: "babeld",
         RD_PBRD: "pbrd",
+        RD_PATH: 'pathd',
     }
 
     def __init__(self, tgen, cls, name, **params):
@@ -714,7 +718,7 @@ class TopoRouter(TopoGear):
         """
         self.logger.debug("stopping")
         self.__stop_internal(False, False)
-        return self.__stop_internal()
+        return self.__stop_internal(True, False)
 
     def startDaemons(self, daemons):
         """
@@ -1114,6 +1118,7 @@ def diagnose_env_linux():
             logger.warning(
                 "BGP topologies are still using exabgp version 3, expect failures"
             )
+        p.close()
 
     # We want to catch all exceptions
     # pylint: disable=W0702
@@ -1122,6 +1127,7 @@ def diagnose_env_linux():
 
     # After we logged the output to file, remove the handler.
     logger.removeHandler(fhandler)
+    fhandler.close()
 
     return ret
 
index f2fafa5e2a91a22fbf1e99e87cf122e174a4be73..88e6f78b922a71dc405b38ca5c4215f339b9acf3 100644 (file)
@@ -43,6 +43,7 @@ from lib.common_config import (
     create_vrf_cfg,
 )
 
+from lib.pim import create_pim_config, create_igmp_config
 from lib.bgp import create_router_bgp
 from lib.ospf import create_router_ospf
 
@@ -68,20 +69,18 @@ def build_topo_from_json(tgen, topo):
             topo["switches"].keys(), key=lambda x: int(re_search("\d+", x).group(0))
         )
 
-    listRouters = ROUTER_LIST[:]
-    listSwitches = SWITCH_LIST[:]
+    listRouters = sorted(ROUTER_LIST[:])
+    listSwitches = sorted(SWITCH_LIST[:])
     listAllRouters = deepcopy(listRouters)
     dictSwitches = {}
 
     for routerN in ROUTER_LIST:
         logger.info("Topo: Add router {}".format(routerN))
         tgen.add_router(routerN)
-        listRouters.append(routerN)
 
     for switchN in SWITCH_LIST:
         logger.info("Topo: Add switch {}".format(switchN))
         dictSwitches[switchN] = tgen.add_switch(switchN)
-        listSwitches.append(switchN)
 
     if "ipv4base" in topo:
         ipv4Next = ipaddress.IPv4Address(topo["link_ip_start"]["ipv4"])
@@ -96,33 +95,25 @@ def build_topo_from_json(tgen, topo):
     for router in listRouters:
         topo["routers"][router]["nextIfname"] = 0
 
+    router_count = 0
     while listRouters != []:
         curRouter = listRouters.pop(0)
         # Physical Interfaces
         if "links" in topo["routers"][curRouter]:
-
-            def link_sort(x):
-                if x == "lo":
-                    return 0
-                elif "link" in x:
-                    return int(x.split("-link")[1])
-                else:
-                    return int(re_search("\d+", x).group(0))
-
             for destRouterLink, data in sorted(
-                topo["routers"][curRouter]["links"].items(),
-                key=lambda x: link_sort(x[0]),
+                topo["routers"][curRouter]["links"].iteritems()
             ):
                 currRouter_lo_json = topo["routers"][curRouter]["links"][destRouterLink]
                 # Loopback interfaces
                 if "type" in data and data["type"] == "loopback":
+                    router_count += 1
                     if (
                         "ipv4" in currRouter_lo_json
                         and currRouter_lo_json["ipv4"] == "auto"
                     ):
                         currRouter_lo_json["ipv4"] = "{}{}.{}/{}".format(
                             topo["lo_prefix"]["ipv4"],
-                            number_to_row(curRouter),
+                            router_count,
                             number_to_column(curRouter),
                             topo["lo_prefix"]["v4mask"],
                         )
@@ -132,7 +123,7 @@ def build_topo_from_json(tgen, topo):
                     ):
                         currRouter_lo_json["ipv6"] = "{}{}:{}/{}".format(
                             topo["lo_prefix"]["ipv6"],
-                            number_to_row(curRouter),
+                            router_count,
                             number_to_column(curRouter),
                             topo["lo_prefix"]["v6mask"],
                         )
@@ -167,6 +158,14 @@ def build_topo_from_json(tgen, topo):
                         destRouter, curRouter, topo["routers"][destRouter]["nextIfname"]
                     )
 
+                    # add link interface
+                    destRouter_link_json["peer-interface"] = "{}-{}-eth{}".format(
+                        curRouter, destRouter, topo["routers"][curRouter]["nextIfname"]
+                    )
+                    currRouter_link_json["peer-interface"] = "{}-{}-eth{}".format(
+                        destRouter, curRouter, topo["routers"][destRouter]["nextIfname"]
+                    )
+
                     topo["routers"][curRouter]["nextIfname"] += 1
                     topo["routers"][destRouter]["nextIfname"] += 1
 
@@ -311,6 +310,8 @@ def build_config_from_json(tgen, topo, save_bkup=True):
             ("prefix_lists", create_prefix_lists),
             ("bgp_community_list", create_bgp_community_lists),
             ("route_maps", create_route_maps),
+            ("pim", create_pim_config),
+            ("igmp", create_igmp_config),
             ("bgp", create_router_bgp),
             ("ospf", create_router_ospf),
         ]
index 4b1886210161637ab88de7e6f9e54d05dee67406..ef0ac271186ff0d6dac50723b4f39051edd54cd0 100644 (file)
@@ -609,8 +609,10 @@ def interface_set_status(node, ifacename, ifaceaction=False, vrf_name=None):
             ifacename, str_ifaceaction
         )
     else:
-        cmd = 'vtysh -c "configure terminal" -c "interface {0} vrf {1}" -c "{2}"'.format(
-            ifacename, vrf_name, str_ifaceaction
+        cmd = (
+            'vtysh -c "configure terminal" -c "interface {0} vrf {1}" -c "{2}"'.format(
+                ifacename, vrf_name, str_ifaceaction
+            )
         )
     node.run(cmd)
 
@@ -910,42 +912,103 @@ def sleep(amount, reason=None):
     time.sleep(amount)
 
 
-def checkAddressSanitizerError(output, router, component):
+def checkAddressSanitizerError(output, router, component, logdir=""):
     "Checks for AddressSanitizer in output. If found, then logs it and returns true, false otherwise"
 
-    addressSantizerError = re.search(
-        "(==[0-9]+==)ERROR: AddressSanitizer: ([^\s]*) ", output
-    )
-    if addressSantizerError:
+    def processAddressSanitizerError(asanErrorRe, output, router, component):
         sys.stderr.write(
             "%s: %s triggered an exception by AddressSanitizer\n" % (router, component)
         )
         # Sanitizer Error found in log
-        pidMark = addressSantizerError.group(1)
-        addressSantizerLog = re.search(
+        pidMark = asanErrorRe.group(1)
+        addressSanitizerLog = re.search(
             "%s(.*)%s" % (pidMark, pidMark), output, re.DOTALL
         )
-        if addressSantizerLog:
-            callingTest = os.path.basename(
-                sys._current_frames().values()[0].f_back.f_back.f_globals["__file__"]
-            )
-            callingProc = sys._getframe(2).f_code.co_name
+        if addressSanitizerLog:
+            # Find Calling Test. Could be multiple steps back
+            testframe = sys._current_frames().values()[0]
+            level = 0
+            while level < 10:
+                test = os.path.splitext(
+                    os.path.basename(testframe.f_globals["__file__"])
+                )[0]
+                if (test != "topotest") and (test != "topogen"):
+                    # Found the calling test
+                    callingTest = os.path.basename(testframe.f_globals["__file__"])
+                    break
+                level = level + 1
+                testframe = testframe.f_back
+            if level >= 10:
+                # somehow couldn't find the test script.
+                callingTest = "unknownTest"
+            #
+            # Now finding Calling Procedure
+            level = 0
+            while level < 20:
+                callingProc = sys._getframe(level).f_code.co_name
+                if (
+                    (callingProc != "processAddressSanitizerError")
+                    and (callingProc != "checkAddressSanitizerError")
+                    and (callingProc != "checkRouterCores")
+                    and (callingProc != "stopRouter")
+                    and (callingProc != "__stop_internal")
+                    and (callingProc != "stop")
+                    and (callingProc != "stop_topology")
+                    and (callingProc != "checkRouterRunning")
+                    and (callingProc != "check_router_running")
+                    and (callingProc != "routers_have_failure")
+                ):
+                    # Found the calling test
+                    break
+                level = level + 1
+            if level >= 20:
+                # something wrong - couldn't found the calling test function
+                callingProc = "unknownProc"
             with open("/tmp/AddressSanitzer.txt", "a") as addrSanFile:
                 sys.stderr.write(
-                    "\n".join(addressSantizerLog.group(1).splitlines()) + "\n"
+                    "AddressSanitizer error in topotest `%s`, test `%s`, router `%s`\n\n"
+                    % (callingTest, callingProc, router)
+                )
+                sys.stderr.write(
+                    "\n".join(addressSanitizerLog.group(1).splitlines()) + "\n"
                 )
-                addrSanFile.write("## Error: %s\n\n" % addressSantizerError.group(2))
+                addrSanFile.write("## Error: %s\n\n" % asanErrorRe.group(2))
                 addrSanFile.write(
                     "### AddressSanitizer error in topotest `%s`, test `%s`, router `%s`\n\n"
                     % (callingTest, callingProc, router)
                 )
                 addrSanFile.write(
                     "    "
-                    + "\n    ".join(addressSantizerLog.group(1).splitlines())
+                    + "\n    ".join(addressSanitizerLog.group(1).splitlines())
                     + "\n"
                 )
                 addrSanFile.write("\n---------------\n")
+        return
+
+    addressSanitizerError = re.search(
+        "(==[0-9]+==)ERROR: AddressSanitizer: ([^\s]*) ", output
+    )
+    if addressSanitizerError:
+        processAddressSanitizerError(addressSanitizerError, output, router, component)
         return True
+
+    # No Address Sanitizer Error in Output. Now check for AddressSanitizer daemon file
+    if logdir:
+        filepattern = logdir + "/" + router + "/" + component + ".asan.*"
+        logger.debug(
+            "Log check for %s on %s, pattern %s\n" % (component, router, filepattern)
+        )
+        for file in glob.glob(filepattern):
+            with open(file, "r") as asanErrorFile:
+                asanError = asanErrorFile.read()
+            addressSanitizerError = re.search(
+                "(==[0-9]+==)ERROR: AddressSanitizer: ([^\s]*) ", asanError
+            )
+            if addressSanitizerError:
+                processAddressSanitizerError(
+                    addressSanitizerError, asanError, router, component
+                )
+                return True
     return False
 
 
@@ -1011,7 +1074,7 @@ class Router(Node):
         if self.logdir is None:
             cur_test = os.environ["PYTEST_CURRENT_TEST"]
             self.logdir = "/tmp/topotests/" + cur_test[
-                0 : cur_test.find(".py")
+                cur_test.find("/") + 1 : cur_test.find(".py")
             ].replace("/", ".")
 
         # If the logdir is not created, then create it and set the
@@ -1019,6 +1082,8 @@ class Router(Node):
         if not os.path.isdir(self.logdir):
             os.system("mkdir -p " + self.logdir + "/" + name)
             os.system("chmod -R go+rw /tmp/topotests")
+            # Erase logs of previous run
+            os.system("rm -rf " + self.logdir + "/" + name)
 
         self.daemondir = None
         self.hasmpls = False
@@ -1040,6 +1105,7 @@ class Router(Node):
             "sharpd": 0,
             "babeld": 0,
             "pbrd": 0,
+            'pathd': 0
         }
         self.daemons_options = {"zebra": ""}
         self.reportCores = True
@@ -1185,7 +1251,7 @@ class Router(Node):
         if self.checkRouterVersion("<", minErrorVersion):
             # ignore errors in old versions
             errors = ""
-        if assertOnError and len(errors) > 0:
+        if assertOnError and errors is not None and len(errors) > 0:
             assert "Errors found - details follow:" == 0, errors
         return errors
 
@@ -1324,6 +1390,7 @@ class Router(Node):
 
         # Starts actual daemons without init (ie restart)
         # cd to per node directory
+        self.cmd("install -d {}/{}".format(self.logdir, self.name))
         self.cmd("cd {}/{}".format(self.logdir, self.name))
         self.cmd("umask 000")
 
@@ -1353,7 +1420,7 @@ class Router(Node):
             zebra_path = os.path.join(self.daemondir, "zebra")
             zebra_option = self.daemons_options["zebra"]
             self.cmd(
-                "{0} {1} --log stdout --log-level debug -s 90000000 -d > zebra.out 2> zebra.err".format(
+                "ASAN_OPTIONS=log_path=zebra.asan {0} {1} --log file:zebra.log --log-level debug -s 90000000 -d > zebra.out 2> zebra.err".format(
                     zebra_path, zebra_option, self.logdir, self.name
                 )
             )
@@ -1368,7 +1435,7 @@ class Router(Node):
             staticd_path = os.path.join(self.daemondir, "staticd")
             staticd_option = self.daemons_options["staticd"]
             self.cmd(
-                "{0} {1} --log stdout --log-level debug -d > staticd.out 2> staticd.err".format(
+                "ASAN_OPTIONS=log_path=staticd.asan {0} {1} --log file:staticd.log --log-level debug -d > staticd.out 2> staticd.err".format(
                     staticd_path, staticd_option, self.logdir, self.name
                 )
             )
@@ -1392,7 +1459,7 @@ class Router(Node):
 
             daemon_path = os.path.join(self.daemondir, daemon)
             self.cmd(
-                "{0} {1} --log stdout --log-level debug -d > {2}.out 2> {2}.err".format(
+                "ASAN_OPTIONS=log_path={2}.asan {0} {1} --log file:{2}.log --log-level debug -d > {2}.out 2> {2}.err".format(
                     daemon_path, self.daemons_options.get(daemon, ""), daemon
                 )
             )
@@ -1514,7 +1581,7 @@ class Router(Node):
                         reportMade = True
                 # Look for AddressSanitizer Errors and append to /tmp/AddressSanitzer.txt if found
                 if checkAddressSanitizerError(
-                    self.getStdErr(daemon), self.name, daemon
+                    self.getStdErr(daemon), self.name, daemon, self.logdir
                 ):
                     sys.stderr.write(
                         "%s: Daemon %s killed by AddressSanitizer" % (self.name, daemon)
@@ -1578,7 +1645,7 @@ class Router(Node):
 
                 # Look for AddressSanitizer Errors and append to /tmp/AddressSanitzer.txt if found
                 if checkAddressSanitizerError(
-                    self.getStdErr(daemon), self.name, daemon
+                    self.getStdErr(daemon), self.name, daemon, self.logdir
                 ):
                     return "%s: Daemon %s not running - killed by AddressSanitizer" % (
                         self.name,
index 6d44d02e5e4f20ebff985cd682872ca6a63b9734..2421b312d210caf2e616ebccb8ac435157fdf439 100644 (file)
@@ -320,8 +320,10 @@ def test_ospf_link_down_kernel_route():
         # Run test function until we get an result. Wait at most 60 seconds.
         test_func = partial(compare_show_ip_route_vrf, router.name, expected)
         result, diff = topotest.run_and_expect(test_func, "", count=140, wait=0.5)
-        assertmsg = 'OSPF IPv4 route mismatch in router "{}" after link down: {}'.format(
-            router.name, diff
+        assertmsg = (
+            'OSPF IPv4 route mismatch in router "{}" after link down: {}'.format(
+                router.name, diff
+            )
         )
         assert result, assertmsg
 
index 95193afb2aae49aaad4e17f6c9ab28d5dc54fff7..24806dd8fcab6f0db543581f7a8bbfb6b95938ab 100644 (file)
@@ -310,7 +310,10 @@ def test_ospf_json():
             # r4 has more interfaces for area 0.0.0.1
             if router.name == "r4":
                 expected["areas"]["0.0.0.1"].update(
-                    {"areaIfActiveCounter": 2, "areaIfTotalCounter": 2,}
+                    {
+                        "areaIfActiveCounter": 2,
+                        "areaIfTotalCounter": 2,
+                    }
                 )
 
         # router 3 has an additional area
@@ -372,16 +375,25 @@ def test_ospf_link_down_kernel_route():
         }
         if router.name == "r1" or router.name == "r2":
             expected.update(
-                {"10.0.10.0/24": None, "172.16.0.0/24": None, "172.16.1.0/24": None,}
+                {
+                    "10.0.10.0/24": None,
+                    "172.16.0.0/24": None,
+                    "172.16.1.0/24": None,
+                }
             )
         elif router.name == "r3" or router.name == "r4":
             expected.update(
-                {"10.0.1.0/24": None, "10.0.2.0/24": None,}
+                {
+                    "10.0.1.0/24": None,
+                    "10.0.2.0/24": None,
+                }
             )
         # Route '10.0.3.0' is no longer available for r4 since it is down.
         if router.name == "r4":
             expected.update(
-                {"10.0.3.0/24": None,}
+                {
+                    "10.0.3.0/24": None,
+                }
             )
         assertmsg = 'OSPF IPv4 route mismatch in router "{}" after link down'.format(
             router.name
@@ -443,12 +455,17 @@ def test_ospf6_link_down_kernel_route():
             )
         elif router.name == "r3" or router.name == "r4":
             expected.update(
-                {"2001:db8:1::/64": None, "2001:db8:2::/64": None,}
+                {
+                    "2001:db8:1::/64": None,
+                    "2001:db8:2::/64": None,
+                }
             )
         # Route '2001:db8:3::/64' is no longer available for r4 since it is down.
         if router.name == "r4":
             expected.update(
-                {"2001:db8:3::/64": None,}
+                {
+                    "2001:db8:3::/64": None,
+                }
             )
         assertmsg = 'OSPF IPv6 route mismatch in router "{}" after link down'.format(
             router.name
diff --git a/tests/topotests/ospf_basic_functionality/ospf_p2mp.json b/tests/topotests/ospf_basic_functionality/ospf_p2mp.json
new file mode 100644 (file)
index 0000000..40815f3
--- /dev/null
@@ -0,0 +1,198 @@
+{
+
+    "ipv4base": "10.0.0.0",
+    "ipv4mask": 24,
+    "link_ip_start": {
+        "ipv4": "10.0.0.0",
+        "v4mask": 24
+    },
+    "lo_prefix": {
+        "ipv4": "1.0.",
+        "v4mask": 32
+    },
+    "routers": {
+        "r0": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "type": "loopback"
+                },
+                "r1": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r3": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                }
+            },
+            "ospf": {
+                "router_id": "100.1.1.0",
+                "neighbors": {
+                    "r1": {},
+                    "r2": {},
+                    "r3": {}
+                }
+            }
+        },
+        "r1": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r3": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r3-link0": {
+                    "ipv4": "auto",
+                    "description": "DummyIntftoR3"
+                }
+            },
+            "ospf": {
+                "router_id": "100.1.1.1",
+                "neighbors": {
+                    "r0": {},
+                    "r2": {},
+                    "r3": {}
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r1": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r3": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                }
+            },
+            "ospf": {
+                "router_id": "100.1.1.2",
+                "neighbors": {
+                    "r1": {},
+                    "r0": {},
+                    "r3": {}
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r1": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r1-link0": {
+                    "ipv4": "auto",
+                    "description": "DummyIntftoR1",
+                    "ospf": {
+                        "area": "0.0.0.0"
+                    }
+                }
+            },
+            "ospf": {
+                "router_id": "100.1.1.3",
+                "neighbors": {
+                    "r0": {},
+                    "r1": {},
+                    "r2": {}
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
index e92baefabfd778d892390f22f887b2bd283285b4..9c3be5893707ebfdfd9e701dd14d512a7bb56c6f 100644 (file)
@@ -29,6 +29,7 @@ import pytest
 from time import sleep
 from copy import deepcopy
 import json
+from lib.topotest import frr_unicode
 
 # Save the Current Working Directory to find configuration files.
 CWD = os.path.dirname(os.path.realpath(__file__))
@@ -318,7 +319,7 @@ def test_ospf_authentication_simple_pass_tc28_p1(request):
     topo_modify_change_ip = deepcopy(topo)
     intf_ip = topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"]
     topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"] = str(
-        IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+        IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
     ) + "/{}".format(intf_ip.split("/")[1])
 
     build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
@@ -529,7 +530,7 @@ def test_ospf_authentication_md5_tc29_p1(request):
     intf_ip = topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"]
 
     topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"] = str(
-        IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+        IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
     ) + "/{}".format(intf_ip.split("/")[1])
 
     build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
index 3b37b8a92f51262c14738b5cd24f25f8ab3f7afe..441368e8fa040aa952b2e7aa0e924923b0347580 100644 (file)
@@ -65,6 +65,7 @@ from lib.ospf import (
     verify_ospf_rib,
     create_router_ospf,
     verify_ospf_interface,
+    redistribute_ospf,
 )
 
 topo = None
@@ -184,38 +185,6 @@ def teardown_module(mod):
     logger.info("=" * 40)
 
 
-def red_static(dut, config=True):
-    """Local def for Redstribute static routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
-    else:
-        ospf_red = {
-            dut: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
-    """Local def for Redstribute connected routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "connected", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
 # ##################################
 # Test cases start here.
 # ##################################
@@ -252,7 +221,11 @@ def test_ospf_ecmp_tc16_p0(request):
     input_dict = {
         "r0": {
             "static_routes": [
-                {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
+                {
+                    "network": NETWORK["ipv4"][0],
+                    "no_of_ip": 5,
+                    "next_hop": "Null0",
+                }
             ]
         }
     }
@@ -260,7 +233,7 @@ def test_ospf_ecmp_tc16_p0(request):
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     dut = "r0"
-    red_static(dut)
+    redistribute_ospf(tgen, topo, dut, "static")
 
     step("Verify that route in R2 in stalled with 8 next hops.")
     nh = []
@@ -341,7 +314,7 @@ def test_ospf_ecmp_tc16_p0(request):
     step(" Un configure static route on R0")
 
     dut = "r0"
-    red_static(dut, config=False)
+    redistribute_ospf(tgen, topo, dut, "static", delete=True)
 
     # Wait for R0 to flush external LSAs.
     sleep(10)
@@ -372,7 +345,7 @@ def test_ospf_ecmp_tc16_p0(request):
 
     step("Re configure the static route in R0.")
     dut = "r0"
-    red_static(dut)
+    redistribute_ospf(tgen, topo, dut, "static")
 
     dut = "r1"
     result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
@@ -415,7 +388,11 @@ def test_ospf_ecmp_tc17_p0(request):
     input_dict = {
         "r0": {
             "static_routes": [
-                {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
+                {
+                    "network": NETWORK["ipv4"][0],
+                    "no_of_ip": 5,
+                    "next_hop": "Null0",
+                }
             ]
         }
     }
@@ -423,7 +400,7 @@ def test_ospf_ecmp_tc17_p0(request):
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     dut = "r0"
-    red_static(dut)
+    redistribute_ospf(tgen, topo, dut, "static")
 
     step("Verify that route in R2 in stalled with 2 next hops.")
 
@@ -442,7 +419,7 @@ def test_ospf_ecmp_tc17_p0(request):
     step(" Un configure static route on R0")
 
     dut = "r0"
-    red_static(dut, config=False)
+    redistribute_ospf(tgen, topo, dut, "static", delete=True)
     # sleep till the route gets withdrawn
     sleep(10)
 
@@ -472,7 +449,7 @@ def test_ospf_ecmp_tc17_p0(request):
 
     step("Reconfigure the static route in R0.Change ECMP value to 2.")
     dut = "r0"
-    red_static(dut)
+    redistribute_ospf(tgen, topo, dut, "static")
 
     step("Configure cost on R0 as 100")
     r0_ospf_cost = {"r0": {"links": {"r1": {"ospf": {"cost": 100}}}}}
index 967bc448790d3402df35d26a0ec885acd21cf538..2da1dcd21ab53a0a0abd14c824b02c263bb37b84 100644 (file)
@@ -66,6 +66,7 @@ from lib.ospf import (
     verify_ospf_rib,
     create_router_ospf,
     verify_ospf_interface,
+    redistribute_ospf,
 )
 from ipaddress import IPv4Address
 
@@ -187,42 +188,6 @@ def teardown_module():
         pass
 
 
-def red_static(dut, config=True):
-    """Local def for Redstribute static routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "static", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
-    """Local def for Redstribute connected routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "connected", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
 # ##################################
 # Test cases start here.
 # ##################################
@@ -275,7 +240,7 @@ def test_ospf_lan_ecmp_tc18_p0(request):
         )
 
         dut = rtr
-        red_static(dut)
+        redistribute_ospf(tgen, topo, dut, "static")
 
     step(
         "Verify that route in R0 in stalled with 8 hops. "
index 1357a86c81b85d54d1cc472c50d6b80fc4ee2c36..dac32090bcc7136c39d9a642d1d50928631d91d2 100644 (file)
@@ -29,6 +29,7 @@ import pytest
 import json
 from copy import deepcopy
 import ipaddress
+from lib.topotest import frr_unicode
 
 # Save the Current Working Directory to find configuration files.
 CWD = os.path.dirname(os.path.realpath(__file__))
@@ -182,42 +183,6 @@ def teardown_module():
         pass
 
 
-def red_static(dut, config=True):
-    """Local def for Redstribute static routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "static", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
-    """Local def for Redstribute connected routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "connected", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
 # ##################################
 # Test cases start here.
 # ##################################
@@ -468,7 +433,7 @@ def test_ospf_lan_tc1_p0(request):
     topo_modify_change_ip = deepcopy(topo)
     intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
     topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"] = str(
-        IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+        IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
     ) + "/{}".format(intf_ip.split("/")[1])
 
     build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
@@ -601,7 +566,7 @@ def test_ospf_lan_tc2_p0(request):
     topo_modify_change_ip = deepcopy(topo)
     intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
     topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"] = str(
-        IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+        IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
     ) + "/{}".format(intf_ip.split("/")[1])
 
     build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
@@ -652,7 +617,7 @@ def test_ospf_lan_tc2_p0(request):
     topo_modify_change_ip = deepcopy(topo)
     intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
     topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"] = str(
-        IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+        IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
     ) + "/{}".format(int(intf_ip.split("/")[1]) + 1)
 
     build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
index 82a34d046cdd72f384f80ee8209426c62cd23492..3644bff3dcaeff9839aec7acb8e9ec6aa2980716 100644 (file)
@@ -30,6 +30,7 @@ from lib.ospf import (
     verify_ospf_rib,
     create_router_ospf,
     verify_ospf_interface,
+    redistribute_ospf,
 )
 from lib.topojson import build_topo_from_json, build_config_from_json
 from lib.topolog import logger
@@ -181,38 +182,6 @@ def teardown_module(mod):
     logger.info("=" * 40)
 
 
-def red_static(dut, config=True):
-    """Local def for Redstribute static routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
-    else:
-        ospf_red = {
-            dut: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
-    """Local def for Redstribute connected routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "connected", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
 # ##################################
 # Test cases start here.
 # ##################################
@@ -268,7 +237,7 @@ def test_ospf_learning_tc15_p0(request):
 
     step("Redistribute static route in R2 ospf.")
     dut = "r2"
-    red_static(dut)
+    redistribute_ospf(tgen, topo, dut, "static")
 
     step("Verify that Type 5 LSA is originated by R2.")
     dut = "r0"
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py
new file mode 100644 (file)
index 0000000..c90275e
--- /dev/null
@@ -0,0 +1,416 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+
+"""OSPF Basic Functionality Automation."""
+import os
+import sys
+import time
+import pytest
+import json
+from copy import deepcopy
+from ipaddress import IPv4Address
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+import ipaddress
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+    start_topology,
+    write_test_header,
+    write_test_footer,
+    reset_config_on_routers,
+    verify_rib,
+    create_static_routes,
+    step,
+    create_route_maps,
+    shutdown_bringup_interface,
+    create_interfaces_cfg,
+    topo_daemons,
+)
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+from lib.ospf import (
+    verify_ospf_neighbor,
+    config_ospf_interface,
+    clear_ospf,
+    verify_ospf_rib,
+    create_router_ospf,
+    verify_ospf_interface,
+    verify_ospf_database,
+)
+
+# Global variables
+topo = None
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospf_p2mp.json".format(CWD)
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+
+"""
+TOPOOLOGY =
+      Please view in a fixed-width font such as Courier.
+      +---+  A1       +---+
+      +R1 +------------+R2 |
+      +-+-+-           +--++
+        |  --        --  |
+        |    -- A0 --    |
+      A0|      ----      |
+        |      ----      | A2
+        |    --    --    |
+        |  --        --  |
+      +-+-+-            +-+-+
+      +R0 +-------------+R3 |
+      +---+     A3     +---+
+
+TESTCASES =
+1. OSPF P2MP -Verify state change events on p2mp network.
+ """
+
+
+class CreateTopo(Topo):
+    """
+    Test topology builder.
+
+    * `Topo`: Topology object
+    """
+
+    def build(self, *_args, **_opts):
+        """Build function."""
+        tgen = get_topogen(self)
+
+        # Building topology from json file
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    """
+    Sets up the pytest environment
+
+    * `mod`: module name
+    """
+    global topo
+    testsuite_run_time = time.asctime(time.localtime(time.time()))
+    logger.info("Testsuite start time: {}".format(testsuite_run_time))
+    logger.info("=" * 40)
+
+    logger.info("Running setup_module to create topology")
+
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(CreateTopo, mod.__name__)
+    # ... and here it calls Mininet initialization functions.
+
+    # get list of daemons needs to be started for this suite.
+    daemons = topo_daemons(tgen, topo)
+
+    # Starting topology, create tmp files which are loaded to routers
+    #  to start deamons and then start routers
+    start_topology(tgen, daemons)
+
+    # Creating configuration from JSON
+    build_config_from_json(tgen, topo)
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+
+    logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+    """
+    Teardown the pytest environment.
+
+    * `mod`: module name
+    """
+
+    logger.info("Running teardown_module to delete topology")
+
+    tgen = get_topogen()
+
+    # Stop toplogy and Remove tmp files
+    tgen.stop_topology()
+
+    logger.info(
+        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+    )
+    logger.info("=" * 40)
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+
+
+def test_ospf_p2mp_tc1_p0(request):
+    """OSPF IFSM -Verify state change events on p2mp network."""
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    global topo
+    step("Bring up the base config as per the topology")
+    reset_config_on_routers(tgen)
+    step(
+        "Verify that OSPF is subscribed to multi cast services "
+        "(All SPF, all DR Routers)."
+    )
+    step("Verify that interface is enabled in ospf.")
+    step("Verify that config is successful.")
+    dut = "r0"
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {"ospf": {"mcastMemberOspfAllRouters": True, "ospfEnabled": True}}
+            }
+        }
+    }
+    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Delete the ip address")
+    topo1 = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "ipv4": topo["routers"]["r0"]["links"]["r3"]["ipv4"],
+                    "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+                    "delete": True,
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, topo1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Change the ip on the R0 interface")
+
+    topo_modify_change_ip = deepcopy(topo)
+    intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
+    topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] = str(
+        IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+    ) + "/{}".format(intf_ip.split("/")[1])
+
+    build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+    step("Verify that interface is enabled in ospf.")
+    dut = "r0"
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "ospf": {
+                        "ipAddress": topo_modify_change_ip["routers"]["r0"]["links"][
+                            "r3"
+                        ]["ipv4"].split("/")[0],
+                        "ipAddressPrefixlen": int(
+                            topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+                                "ipv4"
+                            ].split("/")[1]
+                        ),
+                    }
+                }
+            }
+        }
+    }
+    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Modify the mask on the R0 interface")
+    ip_addr = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
+    mask = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
+    step("Delete the ip address")
+    topo1 = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "ipv4": ip_addr,
+                    "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+                    "delete": True,
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, topo1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Change the ip on the R0 interface")
+
+    topo_modify_change_ip = deepcopy(topo)
+    intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
+    topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] = str(
+        IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+    ) + "/{}".format(int(intf_ip.split("/")[1]) + 1)
+
+    build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+    step("Verify that interface is enabled in ospf.")
+    dut = "r0"
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "ospf": {
+                        "ipAddress": topo_modify_change_ip["routers"]["r0"]["links"][
+                            "r3"
+                        ]["ipv4"].split("/")[0],
+                        "ipAddressPrefixlen": int(
+                            topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+                                "ipv4"
+                            ].split("/")[1]
+                        ),
+                    }
+                }
+            }
+        }
+    }
+    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    topo1 = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "ipv4": topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+                        "ipv4"
+                    ],
+                    "interface": topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+                        "interface"
+                    ],
+                    "delete": True,
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, topo1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    build_config_from_json(tgen, topo, save_bkup=False)
+
+    step("Change the area id on the interface")
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+                    "ospf": {"area": "0.0.0.0"},
+                    "delete": True,
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, input_dict)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+                    "ospf": {"area": "0.0.0.1"},
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, input_dict)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+    step("Verify that interface is enabled in ospf.")
+    dut = "r0"
+    input_dict = {
+        "r0": {"links": {"r3": {"ospf": {"area": "0.0.0.1", "ospfEnabled": True}}}}
+    }
+    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+                    "ospf": {"area": "0.0.0.1"},
+                    "delete": True,
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, input_dict)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+                    "ospf": {"area": "0.0.0.0"},
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, input_dict)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step("Verify if interface is enabled with network type P2MP")
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "networkType":"POINTOMULTIPOINT"
+                    },
+                }
+            }
+        }
+    }
+    result = create_interfaces_cfg(tgen, input_dict)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index 64edc1ebbf99f0b91b90830276938ab322dede7a..ceadb3975b0895d945de2a186d32bef096e5cb6c 100644 (file)
@@ -62,6 +62,7 @@ from lib.ospf import (
     verify_ospf_rib,
     create_router_ospf,
     verify_ospf_database,
+    redistribute_ospf,
 )
 
 # Global variables
@@ -198,6 +199,255 @@ def teardown_module(mod):
 # ##################################
 
 
+def test_ospf_routemaps_functionality_tc19_p0(request):
+    """
+    OSPF Route map - Verify OSPF route map support functionality.
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    global topo
+    step("Bring up the base config as per the topology")
+    reset_config_on_routers(tgen)
+
+    step("Create static routes(10.0.20.1/32 and 10.0.20.2/32) in R0")
+    # Create Static routes
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv4"][0],
+                    "no_of_ip": 5,
+                    "next_hop": "Null0",
+                }
+            ]
+        }
+    }
+    result = create_static_routes(tgen, input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    redistribute_ospf(tgen, topo, "r0", "static")
+
+    dut = "r1"
+    lsid = NETWORK["ipv4"][0].split("/")[0]
+    rid = routerids[0]
+    protocol = "ospf"
+    result = verify_ospf_rib(tgen, dut, input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    redistribute_ospf(tgen, topo, "r0", "static", delete=True)
+
+    step(
+        "Create prefix-list in R0 to permit 10.0.20.1/32 prefix &" " deny 10.0.20.2/32"
+    )
+
+    # Create ip prefix list
+    pfx_list = {
+        "r0": {
+            "prefix_lists": {
+                "ipv4": {
+                    "pf_list_1_ipv4": [
+                        {
+                            "seqid": 10,
+                            "network": NETWORK["ipv4"][0],
+                            "action": "permit",
+                        },
+                        {"seqid": 11, "network": "any", "action": "deny"},
+                    ]
+                }
+            }
+        }
+    }
+    result = create_prefix_lists(tgen, pfx_list)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    # Create route map
+    routemaps = {
+        "r0": {
+            "route_maps": {
+                "rmap_ipv4": [
+                    {
+                        "action": "permit",
+                        "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+                    }
+                ]
+            }
+        }
+    }
+    result = create_route_maps(tgen, routemaps)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Configure route map rmap1 and redistribute static routes to"
+        " ospf using route map rmap1"
+    )
+
+    redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
+
+    step("Change prefix rules to permit 10.0.20.2 and deny 10.0.20.1")
+    # Create ip prefix list
+    pfx_list = {
+        "r0": {
+            "prefix_lists": {
+                "ipv4": {
+                    "pf_list_1_ipv4": [
+                        {
+                            "seqid": 10,
+                            "network": NETWORK["ipv4"][1],
+                            "action": "permit",
+                        },
+                        {"seqid": 11, "network": "any", "action": "deny"},
+                    ]
+                }
+            }
+        }
+    }
+    result = create_prefix_lists(tgen, pfx_list)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Verify that route 10.0.20.2 is allowed and 10.0.20.1 is denied.")
+    dut = "r1"
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {"network": NETWORK["ipv4"][1], "no_of_ip": 1, "next_hop": "Null0"}
+            ]
+        }
+    }
+    result = verify_ospf_rib(tgen, dut, input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {"network": NETWORK["ipv4"][0], "no_of_ip": 1, "next_hop": "Null0"}
+            ]
+        }
+    }
+    result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result
+    )
+
+    result = verify_rib(
+        tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
+    )
+    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result
+    )
+
+    step("Delete and reconfigure prefix list.")
+    # Create ip prefix list
+    pfx_list = {
+        "r0": {
+            "prefix_lists": {
+                "ipv4": {
+                    "pf_list_1_ipv4": [
+                        {
+                            "seqid": 10,
+                            "network": NETWORK["ipv4"][1],
+                            "action": "permit",
+                            "delete": True,
+                        },
+                        {
+                            "seqid": 11,
+                            "network": "any",
+                            "action": "deny",
+                            "delete": True,
+                        },
+                    ]
+                }
+            }
+        }
+    }
+    result = create_prefix_lists(tgen, pfx_list)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_prefix_lists(tgen, pfx_list)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0"}
+            ]
+        }
+    }
+    result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result
+    )
+
+    result = verify_rib(
+        tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
+    )
+    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result
+    )
+
+    pfx_list = {
+        "r0": {
+            "prefix_lists": {
+                "ipv4": {
+                    "pf_list_1_ipv4": [
+                        {
+                            "seqid": 10,
+                            "network": NETWORK["ipv4"][1],
+                            "action": "permit",
+                        },
+                        {"seqid": 11, "network": "any", "action": "deny"},
+                    ]
+                }
+            }
+        }
+    }
+    result = create_prefix_lists(tgen, pfx_list)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Verify that route 10.0.20.2 is allowed and 10.0.20.1 is denied.")
+    dut = "r1"
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {"network": NETWORK["ipv4"][1], "no_of_ip": 1, "next_hop": "Null0"}
+            ]
+        }
+    }
+    result = verify_ospf_rib(tgen, dut, input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {"network": NETWORK["ipv4"][0], "no_of_ip": 1, "next_hop": "Null0"}
+            ]
+        }
+    }
+    result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
+    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result
+    )
+
+    result = verify_rib(
+        tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
+    )
+    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result
+    )
+
+    write_test_footer(tc_name)
+
+
 def test_ospf_routemaps_functionality_tc20_p0(request):
     """
     OSPF route map support functionality.
@@ -218,7 +468,11 @@ def test_ospf_routemaps_functionality_tc20_p0(request):
     input_dict = {
         "r0": {
             "static_routes": [
-                {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
+                {
+                    "network": NETWORK["ipv4"][0],
+                    "no_of_ip": 5,
+                    "next_hop": "Null0",
+                }
             ]
         }
     }
@@ -226,15 +480,7 @@ def test_ospf_routemaps_functionality_tc20_p0(request):
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     step("Redistribute to ospf using route map ( non existent route map)")
-    ospf_red_r1 = {
-        "r0": {
-            "ospf": {
-                "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
-            }
-        }
-    }
-    result = create_router_ospf(tgen, topo, ospf_red_r1)
-    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+    redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
 
     step(
         "Verify that routes are not allowed in OSPF even tough no "
@@ -329,6 +575,242 @@ def test_ospf_routemaps_functionality_tc20_p0(request):
     write_test_footer(tc_name)
 
 
+def test_ospf_routemaps_functionality_tc21_p0(request):
+    """
+    OSPF route map support functionality.
+
+    Verify OSPF route map support functionality with set/match clauses
+    /call/continue/goto in a route-map to see if it takes immediate effect.
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    global topo
+    step("Bring up the base config as per the topology")
+    reset_config_on_routers(tgen)
+
+    step(
+        "Create static routes(10.0.20.1/32) in R1 and redistribute "
+        "to OSPF using route map."
+    )
+
+    # Create Static routes
+    input_dict = {
+        "r0": {
+            "static_routes": [
+                {
+                    "network": NETWORK["ipv4"][0],
+                    "no_of_ip": 5,
+                    "next_hop": "Null0",
+                }
+            ]
+        }
+    }
+    result = create_static_routes(tgen, input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
+
+    # Create route map
+    routemaps = {
+        "r0": {"route_maps": {"rmap_ipv4": [{"action": "permit", "seq_id": 10}]}}
+    }
+    result = create_route_maps(tgen, routemaps)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Verify that route is advertised to R2.")
+    dut = "r1"
+    protocol = "ospf"
+    result = verify_ospf_rib(tgen, dut, input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+    # Create route map
+    routemaps = {
+        "r0": {
+            "route_maps": {
+                "rmap_ipv4": [{"action": "permit", "delete": True, "seq_id": 10}]
+            }
+        }
+    }
+    result = create_route_maps(tgen, routemaps)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step(" Configure route map with set clause (set metric)")
+    # Create route map
+    routemaps = {
+        "r0": {
+            "route_maps": {
+                "rmap_ipv4": [{"action": "permit", "set": {"med": 123}, "seq_id": 10}]
+            }
+        }
+    }
+    result = create_route_maps(tgen, routemaps)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Verify that configured metric is applied to ospf routes.")
+    dut = "r1"
+    protocol = "ospf"
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Configure route map with match clause (match metric) with "
+        "some actions(change metric)."
+    )
+    # Create route map
+    routemaps = {
+        "r0": {
+            "route_maps": {
+                "rmap_ipv4": [
+                    {
+                        "action": "permit",
+                        "match": {"med": 123},
+                        "set": {"med": 150},
+                        "seq_id": 10,
+                    }
+                ]
+            }
+        }
+    }
+    result = create_route_maps(tgen, routemaps)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Configure route map with call clause")
+
+    # Create ip prefix list
+    input_dict_2 = {
+        "r0": {
+            "prefix_lists": {
+                "ipv4": {
+                    "pf_list_1_ipv4": [
+                        {"seqid": 10, "network": "any", "action": "permit"}
+                    ]
+                }
+            }
+        }
+    }
+    result = create_prefix_lists(tgen, input_dict_2)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    # Create route map
+    input_dict_3 = {
+        "r0": {
+            "route_maps": {
+                "rmap_ipv4": [
+                    {
+                        "action": "permit",
+                        "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+                        "set": {"med": 150},
+                        "call": "rmap_match_pf_2_ipv4",
+                        "seq_id": 10,
+                    }
+                ],
+                "rmap_match_pf_2_ipv4": [
+                    {
+                        "action": "permit",
+                        "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+                        "set": {"med": 200},
+                        "seq_id": 10,
+                    }
+                ],
+            }
+        }
+    }
+    result = create_route_maps(tgen, input_dict_3)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_ospf_rib(tgen, dut, input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    # Create route map
+    routemaps = {"r0": {"route_maps": {"rmap_ipv4": [{"delete": True}]}}}
+    result = create_route_maps(tgen, routemaps)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Configure route map with continue clause")
+
+    # Create route map
+    input_dict_3 = {
+        "r0": {
+            "route_maps": {
+                "rmap_ipv4": [
+                    {
+                        "action": "permit",
+                        "seq_id": "10",
+                        "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+                        "set": {"med": 150},
+                        "continue": "30",
+                        "seq_id": 10,
+                    },
+                    {
+                        "action": "permit",
+                        "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+                        "set": {"med": 100},
+                        "seq_id": 20,
+                    },
+                    {
+                        "action": "permit",
+                        "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+                        "set": {"med": 50},
+                        "seq_id": 30,
+                    },
+                ]
+            }
+        }
+    }
+    result = create_route_maps(tgen, input_dict_3)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_ospf_rib(tgen, dut, input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Configure route map with goto clause")
+    # Create route map
+    input_dict_3 = {
+        "r0": {
+            "route_maps": {
+                "rmap_ipv4": [
+                    {
+                        "action": "permit",
+                        "seq_id": "10",
+                        "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+                        "goto": "30",
+                    },
+                    {
+                        "action": "permit",
+                        "seq_id": "20",
+                        "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+                        "set": {"med": 100},
+                    },
+                    {
+                        "action": "permit",
+                        "seq_id": "30",
+                        "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+                        "set": {"med": 200},
+                    },
+                ]
+            }
+        }
+    }
+    result = create_route_maps(tgen, input_dict_3)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    write_test_footer(tc_name)
+
+
 def test_ospf_routemaps_functionality_tc24_p0(request):
     """
     OSPF Route map - Multiple set clauses.
@@ -353,22 +835,18 @@ def test_ospf_routemaps_functionality_tc24_p0(request):
     input_dict = {
         "r0": {
             "static_routes": [
-                {"network": NETWORK["ipv4"][0], "no_of_ip": 1, "next_hop": "Null0",}
+                {
+                    "network": NETWORK["ipv4"][0],
+                    "no_of_ip": 1,
+                    "next_hop": "Null0",
+                }
             ]
         }
     }
     result = create_static_routes(tgen, input_dict)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
-    ospf_red_r0 = {
-        "r0": {
-            "ospf": {
-                "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
-            }
-        }
-    }
-    result = create_router_ospf(tgen, topo, ospf_red_r0)
-    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+    redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
 
     # Create ip prefix list
     pfx_list = {
@@ -387,9 +865,10 @@ def test_ospf_routemaps_functionality_tc24_p0(request):
 
     step("verify that prefix-list is created in R0.")
     result = verify_prefix_lists(tgen, pfx_list)
-    assert result is not True, (
-        "Testcase {} : Failed \n Prefix list not "
-        "present. Error: {}".format(tc_name, result)
+    assert (
+        result is not True
+    ), "Testcase {} : Failed \n Prefix list not " "present. Error: {}".format(
+        tc_name, result
     )
 
     # Create route map
@@ -455,9 +934,10 @@ def test_ospf_routemaps_functionality_tc24_p0(request):
 
     step("verify that prefix-list is created in R0.")
     result = verify_prefix_lists(tgen, pfx_list)
-    assert result is not True, (
-        "Testcase {} : Failed \n Prefix list not "
-        "present. Error: {}".format(tc_name, result)
+    assert (
+        result is not True
+    ), "Testcase {} : Failed \n Prefix list not " "present. Error: {}".format(
+        tc_name, result
     )
 
     # Create route map
index 6ac0b515df9fc397f5dfd6fdb236070426b7fa14..5aa2779aee5a8e99adcea8bec9d92a9940c57699 100644 (file)
@@ -61,6 +61,7 @@ from lib.ospf import (
     clear_ospf,
     verify_ospf_rib,
     create_router_ospf,
+    redistribute_ospf,
 )
 
 # Global variables
@@ -183,42 +184,6 @@ def teardown_module(mod):
     logger.info("=" * 40)
 
 
-def red_static(dut, config=True):
-    """Local def for Redstribute static routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "static", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
-    """Local def for Redstribute connected routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "connected", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
 # ##################################
 # Test cases start here.
 # ##################################
@@ -407,7 +372,13 @@ def test_ospf_redistribution_tc6_p0(request):
 
     protocol = "ospf"
     result = verify_rib(
-        tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh, expected=False,
+        tgen,
+        "ipv4",
+        dut,
+        input_dict,
+        protocol=protocol,
+        next_hop=nh,
+        expected=False,
     )
     assert result is not True, "Testcase {} : Failed \n Error: {}".format(
         tc_name, result
@@ -480,8 +451,8 @@ def test_ospf_redistribution_tc8_p1(request):
         "advertised/exchaged via ospf"
     )
     for rtr in topo["routers"]:
-        red_static(rtr)
-        red_connected(rtr)
+        redistribute_ospf(tgen, topo, rtr, "static")
+        redistribute_ospf(tgen, topo, rtr, "connected")
     for node in topo["routers"]:
         input_dict = {
             "r0": {
@@ -538,18 +509,16 @@ def test_ospf_redistribution_tc8_p1(request):
     )
 
     for rtr in topo["routers"]:
-        ospf_red = {
-            rtr: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
-        }
-        result = create_router_ospf(tgen, topo, ospf_red)
-        assert result is True, "Testcase {} : Failed \n Error: {}".format(
-            tc_name, result
-        )
+        redistribute_ospf(tgen, topo, rtr, "static", delete=True)
 
     input_dict = {
         "r0": {
             "static_routes": [
-                {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
+                {
+                    "network": NETWORK["ipv4"][0],
+                    "no_of_ip": 5,
+                    "next_hop": "Null0",
+                }
             ]
         }
     }
index f563637b3c1ca046bae7a415d0195aa4ec1f0be2..6f6b119abcbabdf2b95d8a06b8ca58e941992b5e 100644 (file)
@@ -29,6 +29,7 @@ import pytest
 import json
 from copy import deepcopy
 from ipaddress import IPv4Address
+from lib.topotest import frr_unicode
 
 # Save the Current Working Directory to find configuration files.
 CWD = os.path.dirname(os.path.realpath(__file__))
@@ -233,7 +234,7 @@ def test_ospf_p2p_tc3_p0(request):
     topo_modify_change_ip = deepcopy(topo)
     intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
     topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] = str(
-        IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+        IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
     ) + "/{}".format(intf_ip.split("/")[1])
 
     build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
@@ -284,7 +285,7 @@ def test_ospf_p2p_tc3_p0(request):
     topo_modify_change_ip = deepcopy(topo)
     intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
     topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] = str(
-        IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+        IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
     ) + "/{}".format(int(intf_ip.split("/")[1]) + 1)
 
     build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
@@ -776,6 +777,205 @@ def test_ospf_show_p1(request):
     write_test_footer(tc_name)
 
 
+def test_ospf_dead_tc11_p0(request):
+    """
+    OSPF timers.
+
+    Verify OSPF interface timer dead interval functionality
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    global topo
+    step("Bring up the base config as per the topology")
+    reset_config_on_routers(tgen)
+
+    step("modify dead interval from default value to some other value on r1")
+
+    topo1 = {
+        "r1": {
+            "links": {
+                "r0": {
+                    "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+                    "ospf": {"hello_interval": 12, "dead_interval": 48},
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, topo1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "verify that new timer value is configured and applied using "
+        "the show ip ospf interface command."
+    )
+    dut = "r1"
+    input_dict = {"r1": {"links": {"r0": {"ospf": {"timerDeadSecs": 48}}}}}
+    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("modify dead interval from default value to r1" "dead interval timer on r2")
+
+    topo1 = {
+        "r0": {
+            "links": {
+                "r1": {
+                    "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+                    "ospf": {"dead_interval": 48, "hello_interval": 12},
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, topo1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("verify that new timer value is configured.")
+    input_dict = {"r0": {"links": {"r1": {"ospf": {"timerDeadSecs": 48}}}}}
+    dut = "r0"
+    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("verify that ospf neighbours are  full")
+    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+    assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+        ospf_covergence
+    )
+
+    step("reconfigure the default dead interval timer value to " "default on r1 and r2")
+    topo1 = {
+        "r0": {
+            "links": {
+                "r1": {
+                    "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+                    "ospf": {"dead_interval": 40},
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, topo1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    topo1 = {
+        "r1": {
+            "links": {
+                "r0": {
+                    "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+                    "ospf": {"dead_interval": 40},
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, topo1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("verify that new timer value is configured.")
+    input_dict = {"r0": {"links": {"r1": {"ospf": {"timerDeadSecs": 40}}}}}
+    dut = "r0"
+    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("verify that ospf neighbours are  full")
+    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+    assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+        ospf_covergence
+    )
+
+    step(" Configure dead timer = 65535 on r1 and r2")
+
+    topo1 = {
+        "r0": {
+            "links": {
+                "r1": {
+                    "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+                    "ospf": {"dead_interval": 65535},
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, topo1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    topo1 = {
+        "r1": {
+            "links": {
+                "r0": {
+                    "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+                    "ospf": {"dead_interval": 65535},
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, topo1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("verify that new timer value is configured.")
+    input_dict = {"r0": {"links": {"r1": {"ospf": {"timerDeadSecs": 65535}}}}}
+    dut = "r0"
+    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("verify that ospf neighbours are  full")
+    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+    assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+        ospf_covergence
+    )
+
+    step(" Try configuring timer values outside range for example 65536")
+    topo1 = {
+        "r0": {
+            "links": {
+                "r1": {
+                    "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+                    "ospf": {"dead_interval": 65536},
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, topo1)
+    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result
+    )
+
+    step("Unconfigure the dead timer from the interface from r1 and r2.")
+
+    topo1 = {
+        "r1": {
+            "links": {
+                "r0": {
+                    "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+                    "ospf": {"dead_interval": 65535},
+                    "delete": True,
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, topo1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that timer value is deleted from intf & " "set to default value 40 sec."
+    )
+    input_dict = {"r1": {"links": {"r0": {"ospf": {"timerDeadSecs": 40}}}}}
+    dut = "r1"
+    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    write_test_footer(tc_name)
+
+
 if __name__ == "__main__":
     args = ["-s"] + sys.argv[1:]
     sys.exit(pytest.main(args))
index fcbe3c0adf67e883570a351a1386e336710238cc..5161d5eec75456acbe99ff9c2a27575149b232f3 100644 (file)
@@ -80,7 +80,7 @@ class NetworkTopo(Topo):
 ##
 #####################################################
 
-
+@pytest.mark.pbr
 def setup_module(module):
     "Setup topology"
     tgen = Topogen(NetworkTopo, module.__name__)
index e8a9f72b483ca96e02781be6ebc5718f7f3cf923..74a7fbf16e113791b3b8765bb5125f1164453df9 100644 (file)
@@ -80,7 +80,7 @@ class PIMTopo(Topo):
         sw.add_link(tgen.gears["r1"])
         sw.add_link(tgen.gears["r3"])
 
-
+@pytest.mark.pim
 def setup_module(mod):
     "Sets up the pytest environment"
     tgen = Topogen(PIMTopo, mod.__name__)
index 6e8e74909230ce23366ba2253fc51e02f577a95c..d1b18a57bbe5da456cef17df28dadc5428ed7241 100644 (file)
@@ -1,6 +1,16 @@
 # Skip pytests example directory
 [pytest]
 norecursedirs = .git example-test example-topojson-test lib docker
+markers =
+       babel: Tests that run against BABEL
+       bfd: Tests that run against BFDD
+       eigrp: Tests that run against EIGRPD
+       isis: Tests that run against ISISD
+       ldp: Tests that run against LDPD
+       ospf: Tests that run against OSPF( v2 and v3 )
+       pbr: Tests that run against PBRD
+       pim: Tests that run against pim
+       rip: Tests that run against RIP, both v4 and v6
 
 [topogen]
 # Default configuration values
index de11b78824c4de51e9c79f717f61c53a9dfd8d75..edad1ff65d0e7854ef1622f727048d592614f3c1 100644 (file)
@@ -104,7 +104,7 @@ class NetworkTopo(Topo):
 ##
 #####################################################
 
-
+@pytest.mark.rip
 def setup_module(module):
     global topo, net
 
@@ -352,9 +352,11 @@ def test_zebra_ipv4_routingTable():
             else:
                 print("r%s ok" % i)
 
-            assert failures == 0, (
-                "Zebra IPv4 Routing Table verification failed for router r%s:\n%s"
-                % (i, diff)
+            assert (
+                failures == 0
+            ), "Zebra IPv4 Routing Table verification failed for router r%s:\n%s" % (
+                i,
+                diff,
             )
 
     # Make sure that all daemons are still running
index 2976cdefe48629ed23f39d4b3edbbb0e48bd3c43..47b63e5b264b4469ebad8655769e235b0e1188d7 100644 (file)
@@ -104,7 +104,7 @@ class NetworkTopo(Topo):
 ##
 #####################################################
 
-
+@pytest.mark.rip
 def setup_module(module):
     global topo, net
 
@@ -373,9 +373,11 @@ def test_zebra_ipv6_routingTable():
             else:
                 print("r%s ok" % i)
 
-            assert failures == 0, (
-                "Zebra IPv6 Routing Table verification failed for router r%s:\n%s"
-                % (i, diff)
+            assert (
+                failures == 0
+            ), "Zebra IPv6 Routing Table verification failed for router r%s:\n%s" % (
+                i,
+                diff,
             )
 
     # Make sure that all daemons are running
index 24a45dca81b39461aa98f008f7c19d9421a50d32..25d209f9eb4ee5a1c4815b1a2118fbb098af9cbb 100644 (file)
@@ -6,11 +6,11 @@
       "type":"connected"
     },
     {
-      "fib":200000,
-      "rib":200000,
+      "fib":1000000,
+      "rib":1000000,
       "type":"sharp"
     }
   ],
-  "routesTotal":200032,
-  "routesTotalFib":200032
+  "routesTotal":1000032,
+  "routesTotalFib":1000032
 }
diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo1_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo1_ebgp.json
new file mode 100644 (file)
index 0000000..7099043
--- /dev/null
@@ -0,0 +1,157 @@
+{
+    "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-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+                                    "dest_link": {
+                                        "r2": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+                                    "dest_link": {
+                                        "r2": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "200",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo2_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo2_ebgp.json
new file mode 100644 (file)
index 0000000..91820b0
--- /dev/null
@@ -0,0 +1,363 @@
+{
+    "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-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "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"
+                }
+            },
+            "bgp": {
+                "local_as": "200",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link1": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link2": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link3": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link4": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link5": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link6": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link7": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            },
+                            "redistribute": [{
+                                "redist_type": "static"
+                            }]
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link1": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link2": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link3": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link4": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link5": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link6": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link7": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            },
+                            "redistribute": [{
+                                "redist_type": "static"
+                            }]
+                        }
+                    }
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "300",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link1": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link2": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link3": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link4": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link5": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link6": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link7": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link1": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link2": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link3": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link4": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link5": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link6": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link7": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo3_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo3_ebgp.json
new file mode 100644 (file)
index 0000000..5246a31
--- /dev/null
@@ -0,0 +1,189 @@
+{
+    "address_types": [
+        "ipv4",
+        "ipv6"
+    ],
+    "ipv4base": "10.0.0.0",
+    "ipv4mask": 30,
+    "ipv6base": "fd00::",
+    "ipv6mask": 64,
+    "link_ip_start": {
+        "ipv4": "10.0.0.0",
+        "v4mask": 29,
+        "ipv6": "fd00::",
+        "v6mask": 64
+    },
+    "lo_prefix": {
+        "ipv4": "1.0.",
+        "v4mask": 32,
+        "ipv6": "2001:db8:f::",
+        "v6mask": 128
+    },
+    "routers": {
+        "r1": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "200",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo4_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo4_ebgp.json
new file mode 100644 (file)
index 0000000..bb72578
--- /dev/null
@@ -0,0 +1,428 @@
+{
+    "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-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "vm4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r1-link0": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r1-link1": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r1-link2": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r1-link3": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r1-link0": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r1-link1": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r1-link2": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r1-link3": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "vm1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "vm2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "vm3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "vm6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "200",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r1": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link1": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link2": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link3": {
+                                            "password": "r1"
+                                        }
+                                    }
+                                },
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link1": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link2": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link3": {
+                                            "password": "r1"
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r1": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link1": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link2": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link3": {
+                                            "password": "r1"
+                                        }
+                                    }
+                                },
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link1": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link2": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link3": {
+                                            "password": "r1"
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "vm5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "300",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link0": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r3-link1": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r3-link2": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r3-link3": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link0": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r3-link1": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r3-link2": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r3-link3": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "vm1": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "vm2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "vm3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "vm4": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "vm5": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "vm6": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py
new file mode 100644 (file)
index 0000000..a33257d
--- /dev/null
@@ -0,0 +1,1261 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+"""
+
+    -Verify static route ECMP functionality with 2 next hop.
+
+    -Verify static route functionality with 2 next hop and different AD
+    value.
+
+    -Verify RIB status when same route advertise via BGP and static route.
+
+"""
+import sys
+import json
+import time
+import os
+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 mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+    start_topology,
+    write_test_header,
+    write_test_footer,
+    reset_config_on_routers,
+    verify_rib,
+    create_static_routes,
+    check_address_types,
+    step,
+    create_interfaces_cfg,
+    shutdown_bringup_interface,
+    stop_router,
+    start_router,
+)
+from lib.topolog import logger
+from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo1_ebgp.json".format(CWD)
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {"ipv4": ["11.0.20.1/32", "11.0.20.2/32"], "ipv6": ["2::1/128", "2::2/128"]}
+NETWORK2 = {"ipv4": "11.0.20.1/32", "ipv6": "2::1/128"}
+
+PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"}
+
+
+class CreateTopo(Topo):
+    """
+    Test CreateTopo - topology 1.
+
+    * `Topo`: Topology object
+    """
+
+    def build(self, *_args, **_opts):
+        """Build function."""
+        tgen = get_topogen(self)
+
+        # Building topology from json file
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    """
+    Sets up the pytest environment.
+
+    * `mod`: module name
+    """
+    global topo
+    testsuite_run_time = time.asctime(time.localtime(time.time()))
+    logger.info("Testsuite start time: {}".format(testsuite_run_time))
+    logger.info("=" * 40)
+
+    logger.info("Running setup_module to create topology")
+
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(CreateTopo, mod.__name__)
+    # ... and here it calls Mininet initialization functions.
+
+    # Starting topology, create tmp files which are loaded to routers
+    #  to start deamons and then start routers
+    start_topology(tgen)
+
+    # Creating configuration from JSON
+    build_config_from_json(tgen, topo)
+
+    if version_cmp(platform.release(), '4.19') < 0:
+        error_msg = ('These tests will not run. (have kernel "{}", '
+            'requires kernel >= 4.19)'.format(platform.release()))
+        pytest.skip(error_msg)
+
+    # Checking BGP convergence
+    global BGP_CONVERGENCE
+    global ADDR_TYPES
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    # Api call verify whether BGP is converged
+    BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+    assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+        BGP_CONVERGENCE
+    )
+
+    logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+    """
+    Teardown the pytest environment.
+
+    * `mod`: module name
+    """
+
+    logger.info("Running teardown_module to delete topology")
+
+    tgen = get_topogen()
+
+    # Stop toplogy and Remove tmp files
+    tgen.stop_topology()
+
+    logger.info(
+        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+    )
+    logger.info("=" * 40)
+
+
+def populate_nh():
+    NEXT_HOP_IP = {
+        "nh1": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0],
+        },
+        "nh2": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0],
+        },
+    }
+    return NEXT_HOP_IP
+
+
+#####################################################
+#
+#   Testcases
+#
+#####################################################
+
+
+def test_static_route_2nh_p0_tc_1_ebgp(request):
+    """
+    Verify static route ECMP functionality with 2 next hop.
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+
+    step(
+        "Configure IPv4 static route (10.1.1.1) in R2 with next hop N1"
+        "(28.1.1.2 ) and N2 (29.1.1.2) , Static route next-hop present on"
+        "R1"
+    )
+    step("ex :- ip route 10.1.1.1/24 28.1.1.2 & ip route 10.1.1.1/24 29.1.1.1")
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                    },
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                    },
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "On R2, static route installed in RIB using show ip route"
+            " with 2 ECMP next hop "
+        )
+        nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert (
+            result is True
+        ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+        step("Configure IBGP IPv4 peering between R2 and R3 router.")
+        step("Configure redistribute static in BGP on R2 router")
+
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Remove the static route configured with nexthop N1 from running config")
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "delete": True,
+                    }
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "On R2, after removing the static route with N1 , "
+            "route become active with nexthop N2 and vice versa."
+        )
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert (
+            result is not True
+        ), "Testcase {} : Failed" "Error: Routes is still present in RIB".format(
+            tc_name
+        )
+
+        nh = [NEXT_HOP_IP["nh2"][addr_type]]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("Configure the static route with nexthop N1")
+
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Remove the static route configured with nexthop N2 from" "running config")
+
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "delete": True,
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "On R2, after removing the static route with N2 , "
+            "route become active with nexthop N1 and vice versa."
+        )
+        nh = NEXT_HOP_IP["nh2"][addr_type]
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB".format(tc_name)
+
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("Configure the static route with nexthop N2")
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Shut nexthop interface N1")
+        intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"]
+
+        shutdown_bringup_interface(tgen, dut, intf, False)
+
+        step("Only one the nexthops should be active in RIB.")
+
+        nh = NEXT_HOP_IP["nh2"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB".format(tc_name)
+
+        dut = "r3"
+        result = verify_bgp_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            protocol=protocol,
+            next_hop=nh,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+        dut = "r2"
+        nh = [NEXT_HOP_IP["nh2"][addr_type]]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        dut = "r3"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Route is"
+        " missing in RIB".format(tc_name)
+
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+        dut = "r2"
+        step("No shut the nexthop interface N1")
+        shutdown_bringup_interface(tgen, dut, intf, True)
+
+        step(
+            "after shut of nexthop N1 , route become active "
+            "with nexthop N2 and vice versa."
+        )
+        nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][addr_type]]
+
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("Shut nexthop interface N2")
+        intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]
+        dut = "r2"
+        shutdown_bringup_interface(tgen, dut, intf, False)
+
+        step(
+            " after shut of nexthop N1 , route become active with "
+            "nexthop N2 and vice versa."
+        )
+        nh = NEXT_HOP_IP["nh2"][addr_type]
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB".format(tc_name)
+
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        dut = "r3"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Route is"
+        " missing in RIB".format(tc_name)
+
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+        step("No shut nexthop interface N2")
+        dut = "r2"
+        shutdown_bringup_interface(tgen, dut, intf, True)
+
+        step(
+            "after shut of nexthop N1 , route become active "
+            "with nexthop N2 and vice versa."
+        )
+        nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][addr_type]]
+
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        dut = "r3"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Route is"
+        " missing in RIB".format(tc_name)
+
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+        step("Reload the FRR router")
+        # stop/start -> restart FRR router and verify
+        stop_router(tgen, "r2")
+
+        start_router(tgen, "r2")
+
+        dut = "r2"
+        step(
+            "After reload of FRR router , static route installed"
+            " in RIB and FIB properly ."
+        )
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        dut = "r3"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_static_route_2nh_admin_dist_p0_tc_2_ebgp(request):
+    """
+    Verify static route functionality with 2 next hop & different AD value.
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+    step(
+        "Configure IPv4 static route (10.1.1.1) in R2 with next hop N1"
+        "(28.1.1.2 ) AD 10 and N2 (29.1.1.2) AD 20 , Static route next-hop"
+        "present on R1 \n ex :- ip route 10.1.1.1/24 28.1.1.2 10 & "
+        "ip route 10.1.1.1/24 29.1.1.2 20"
+    )
+
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    },
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "admin_distance": 20,
+                    },
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "On R2, static route installed in RIB using "
+            "show ip route with 2 next hop , lowest AD nexthop is active "
+        )
+        rte1_nh1 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        "missing in RIB".format(tc_name)
+
+        rte2_nh2 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "admin_distance": 20,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh2"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte2_nh2,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        "not active in RIB".format(tc_name)
+
+        step("Configure IBGP IPv4 peering between R2 and R3 router.")
+        step("Explicit route is added in R3 for R2 nexthop rechability")
+        rt3_rtes = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NEXT_HOP_IP["nh1"][addr_type] + "/32",
+                        "next_hop": topo["routers"]["r2"]["links"]["r3"][addr_type],
+                    },
+                    {
+                        "network": NEXT_HOP_IP["nh2"][addr_type] + "/32",
+                        "next_hop": topo["routers"]["r2"]["links"]["r3"][addr_type],
+                    },
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, rt3_rtes)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+        step("Configure redistribute static in BGP on R2 router")
+
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Remove the static route configured with nexthop N1 from" "running config")
+        rt1_nh1 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                        "delete": True,
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, rt1_nh1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "On R2, after removing the static route with N1 , "
+            "route become active with nexthop N2 and vice versa."
+        )
+        rte1_nh1 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte1_nh1,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        "missing in RIB".format(tc_name)
+
+        rte2_nh2 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "admin_distance": 20,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh2"][addr_type]]
+        result = verify_rib(
+            tgen, addr_type, dut, rte2_nh2, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        "not active in RIB".format(tc_name)
+
+        step("Configure the static route with nexthop N1")
+        rte1_nh1 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, rte1_nh1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Remove the static route configured with nexthop N2 from" "running config")
+        rte2_nh2 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "admin_distance": 20,
+                        "delete": True,
+                    }
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, rte2_nh2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "On R2, after removing the static route with N2 , "
+            "route become active with nexthop N1 and vice versa."
+        )
+        nh = NEXT_HOP_IP["nh2"][addr_type]
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte2_nh2,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB".format(tc_name)
+
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        result = verify_rib(
+            tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("Configure the static route with nexthop N2")
+        rte2_nh2 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "admin_distance": 20,
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, rte2_nh2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Shut nexthop interface N1")
+        intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"]
+
+        shutdown_bringup_interface(tgen, dut, intf, False)
+
+        step("after shut of nexthop N1 , route become active with nexthop N2")
+
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte1_nh1,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB".format(tc_name)
+
+        nh = [NEXT_HOP_IP["nh2"][addr_type]]
+        result = verify_rib(
+            tgen, addr_type, dut, rte2_nh2, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("No shut the nexthop interface N1")
+        shutdown_bringup_interface(tgen, dut, intf, True)
+
+        step(
+            "after shut of nexthop N1 , route become active "
+            "with nexthop N2 and vice versa."
+        )
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+
+        result = verify_rib(
+            tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("Shut nexthop interface N2")
+        intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]
+
+        shutdown_bringup_interface(tgen, dut, intf, False)
+
+        step(
+            " after shut of nexthop N1 , route become active with "
+            "nexthop N2 and vice versa."
+        )
+        nh = NEXT_HOP_IP["nh2"][addr_type]
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte2_nh2,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB".format(tc_name)
+
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        result = verify_rib(
+            tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("No shut nexthop interface N2")
+        shutdown_bringup_interface(tgen, dut, intf, True)
+
+        step(
+            "after shut of nexthop N1 , route become active "
+            "with nexthop N2 and vice versa."
+        )
+        rte1_nh1 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        "missing in RIB".format(tc_name)
+
+        rte2_nh2 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "admin_distance": 20,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh2"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte2_nh2,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        "not active in RIB".format(tc_name)
+
+        dut = "r3"
+        protocol = "bgp"
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte2_nh2,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        "not active in RIB".format(tc_name)
+
+        dut = "r2"
+        step("Reload the FRR router")
+        # stop/start -> restart FRR router and verify
+        stop_router(tgen, "r2")
+
+        start_router(tgen, "r2")
+
+        step(
+            "After reload of FRR router , static route installed"
+            " in RIB and FIB properly ."
+        )
+        rte1_nh1 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        "missing in RIB".format(tc_name)
+
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_bgp_rib(tgen, addr_type, dut, rte1_nh1, next_hop=nh)
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        "missing in RIB".format(tc_name)
+
+        rte2_nh2 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "admin_distance": 20,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh2"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte2_nh2,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        "not active in RIB".format(tc_name)
+
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_bgp_rib(tgen, addr_type, dut, rte2_nh2, next_hop=nh)
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        "not active in RIB".format(tc_name)
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte2_nh2,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        "not active in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_same_rte_from_bgp_static_p0_tc5_ebgp(request):
+    """
+    Verify RIB status when same route advertise via BGP and static
+    route
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    reset_config_on_routers(tgen)
+
+    NEXT_HOP_IP = populate_nh()
+    step("Configure EBGP IPv4 peering between R2 and R3 router.")
+
+    step(
+        "Configure IPv4 static route (10.1.1.1/24) in R2 with next hop"
+        "N1 (28.1.1.2 ) and N2 (29.1.1.2) , Static route next-hop present"
+        "on R1"
+    )
+
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                    },
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                    },
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step("Configure redistribute static in BGP.")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+        step("Verify on R3 , route receive on R3 BGP table ")
+        dut = "r3"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+        step("Verify route installed in the RIB and FIB of R3")
+        protocol = "bgp"
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert result is True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+    step(
+        "Configure 2 links/interfaces between R1 and R3 , keep one"
+        "interface in shut (active) state and other interface in no shut"
+        "(inactive) state"
+    )
+    dut = "r3"
+    intf = topo["routers"]["r3"]["links"]["r1-link0"]["interface"]
+    shutdown_bringup_interface(tgen, dut, intf, False)
+
+    step(
+        "Configure same static route (10.1.1.1/24) in R3 with inactive"
+        "nexthop interface"
+    )
+
+    step(
+        "Configure same static route 10.1.1.1/24) again in R3 with"
+        "active nexthop interface"
+    )
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": topo["routers"]["r1"]["links"]["r3-link0"][
+                            addr_type
+                        ],
+                    },
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": topo["routers"]["r1"]["links"]["r3-link1"][
+                            addr_type
+                        ],
+                    },
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "Verify when static route configure with inactive nexthop , "
+            "verify BGP received route is active in the RIB and FIB"
+        )
+        dut = "r3"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Route is"
+        " missing in BGP RIB".format(tc_name)
+
+        protocol = "bgp"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route is"
+        " missing in RIB".format(tc_name)
+
+    step("Remove the static route on R3 configured with active" "interface")
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": topo["routers"]["r1"]["links"]["r3-link0"][
+                            addr_type
+                        ],
+                        "delete": True,
+                    },
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": topo["routers"]["r1"]["links"]["r3-link1"][
+                            addr_type
+                        ],
+                        "delete": True,
+                    },
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+        step(
+            "After removing the static route with active nexthop verify "
+            "BGP received route is became active in RIB and FIB"
+        )
+        dut = "r3"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Route is"
+        " missing in BGP RIB".format(tc_name)
+
+        protocol = "bgp"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route is"
+        " missing in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py
new file mode 100644 (file)
index 0000000..93320df
--- /dev/null
@@ -0,0 +1,1711 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+
+"""
+    -Verify static route functionality with 8 next hop different AD value
+    and BGP ECMP
+
+    -Verify 8 static route functionality with 8 next hop different AD
+
+    -Verify static route with 8 next hop with different AD value and 8
+    EBGP neighbors
+
+    -Verify static route with 8 next hop with different AD value and 8
+    IBGP neighbors
+
+    -Delete the static route and verify the RIB and FIB state
+
+    -Verify 8 static route functionality with 8 ECMP next hop
+"""
+import sys
+import json
+import time
+import os
+import pytest
+import platform
+import random
+from lib.topotest import version_cmp
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+    start_topology,
+    write_test_header,
+    write_test_footer,
+    reset_config_on_routers,
+    verify_rib,
+    create_static_routes,
+    check_address_types,
+    step,
+    shutdown_bringup_interface,
+    stop_router,
+    start_router,
+)
+from lib.topolog import logger
+from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo2_ebgp.json".format(CWD)
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {
+    "ipv4": [
+        "11.0.20.1/32",
+        "11.0.20.2/32",
+        "11.0.20.3/32",
+        "11.0.20.4/32",
+        "11.0.20.5/32",
+        "11.0.20.6/32",
+        "11.0.20.7/32",
+        "11.0.20.8/32",
+    ],
+    "ipv6": [
+        "2::1/128",
+        "2::2/128",
+        "2::3/128",
+        "2::4/128",
+        "2::5/128",
+        "2::6/128",
+        "2::7/128",
+        "2::8/128",
+    ],
+}
+PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"}
+PREFIX2 = {"ipv4": "110.0.20.2/32", "ipv6": "20::2/128"}
+NEXT_HOP_IP = []
+topo_diag = """
+          Please view in a fixed-width font such as Courier.
+    +------+              +------+              +------+
+    |      +--------------+      +--------------+      |
+    |      |              |      |              |      |
+    |  R1  +---8 links----+ R2   +---8 links----+ R3   |
+    |      |              |      |              |      |
+    |      +--------------+      +--------------+      |
+    +------+              +------+              +------+
+
+"""
+
+
+class CreateTopo(Topo):
+    """
+    Test CreateTopo - topology 1.
+
+    * `Topo`: Topology object
+    """
+
+    def build(self, *_args, **_opts):
+        """Build function."""
+        tgen = get_topogen(self)
+
+        # Building topology from json file
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    """
+
+    Set up the pytest environment.
+
+    * `mod`: module name
+    """
+    global topo
+    testsuite_run_time = time.asctime(time.localtime(time.time()))
+    logger.info("Testsuite start time: {}".format(testsuite_run_time))
+    logger.info("=" * 40)
+
+    logger.info("Running setup_module to create topology")
+
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(CreateTopo, mod.__name__)
+    # ... and here it calls Mininet initialization functions.
+
+    # Starting topology, create tmp files which are loaded to routers
+    #  to start deamons and then start routers
+    start_topology(tgen)
+
+    # Creating configuration from JSON
+    build_config_from_json(tgen, topo)
+
+    if version_cmp(platform.release(), '4.19') < 0:
+        error_msg = ('These tests will not run. (have kernel "{}", '
+            'requires kernel >= 4.19)'.format(platform.release()))
+        pytest.skip(error_msg)
+
+    # Checking BGP convergence
+    global BGP_CONVERGENCE
+    global ADDR_TYPES
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    # Api call verify whether BGP is converged
+    BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+    assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+        BGP_CONVERGENCE
+    )
+
+    logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+    """
+    Teardown the pytest environment
+
+    * `mod`: module name
+    """
+
+    logger.info("Running teardown_module to delete topology")
+
+    tgen = get_topogen()
+
+    # Stop toplogy and Remove tmp files
+    tgen.stop_topology()
+
+    logger.info(
+        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+    )
+    logger.info("=" * 40)
+
+
+def populate_nh():
+    NEXT_HOP_IP = {
+        "nh1": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0],
+        },
+        "nh2": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0],
+        },
+        "nh3": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0],
+        },
+        "nh4": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link3"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link3"]["ipv6"].split("/")[0],
+        },
+        "nh5": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link4"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link4"]["ipv6"].split("/")[0],
+        },
+        "nh6": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link5"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link5"]["ipv6"].split("/")[0],
+        },
+        "nh7": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link6"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link6"]["ipv6"].split("/")[0],
+        },
+        "nh8": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link7"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link7"]["ipv6"].split("/")[0],
+        },
+    }
+    return NEXT_HOP_IP
+
+
+#####################################################
+#
+#   Testcases
+#
+#####################################################
+
+
+def test_static_rte_with_8ecmp_nh_p1_tc9_ebgp(request):
+    """
+    Verify 8 static route functionality with 8 ECMP next hop
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    NEXT_HOP_IP = populate_nh()
+    step("Configure 8 interfaces / links between R1 and R2")
+    step("Configure 8 interfaces / links between R2 and R3")
+    step("Configure 8 IBGP IPv4 peering between R2 and R3 router.")
+    reset_config_on_routers(tgen)
+
+    step(
+        "Configure 8 IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2) , N2(22.1.1.2) , N3(23.1.1.2) , N4(24.1.1.2) ,"
+        "N5(25.1.1.2) , N6(26.1.1.2) , N7(27.1.1.2) , N8(28.1.1.2) ,"
+        "Static route next-hop present on R1"
+    )
+    nh_all = {}
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+        nh_all[addr_type] = [
+            NEXT_HOP_IP["nh1"][addr_type],
+            NEXT_HOP_IP["nh2"][addr_type],
+            NEXT_HOP_IP["nh3"][addr_type],
+            NEXT_HOP_IP["nh4"][addr_type],
+            NEXT_HOP_IP["nh5"][addr_type],
+            NEXT_HOP_IP["nh6"][addr_type],
+            NEXT_HOP_IP["nh7"][addr_type],
+            NEXT_HOP_IP["nh8"][addr_type],
+        ]
+
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh_all[addr_type],
+            protocol=protocol,
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+    step("Configure redistribute static in BGP on R2 router")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+    step(
+        "Remove the static route configured with nexthop N1 to N8, one"
+        "by one from running config"
+    )
+    dut = "r2"
+    protocol = "static"
+    step(
+        "After removing the static route with N1 to N8 one by one , "
+        "verify that entry is removed from RIB and FIB of R3 "
+    )
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+
+            step(
+                "After removing the static route with N1 to N8 one by one , "
+                "verify that entry is removed from RIB and FIB of R3 "
+            )
+            nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type]
+            result = verify_rib(
+                tgen,
+                addr_type,
+                dut,
+                input_dict_4,
+                next_hop=nh,
+                protocol=protocol,
+                expected=False,
+            )
+            assert result is not True, "Testcase {} : Failed\nError: Routes is"
+            " still present in RIB".format(tc_name)
+
+    step("Configure the static route with nexthop N1 to N8, one by one")
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+
+            nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type]
+            result = verify_rib(
+                tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+            )
+            assert result is True, "Testcase {} : Failed\nError: Routes are"
+            " missing in RIB".format(tc_name)
+
+    protocol = "static"
+    step("Random shut of the nexthop interfaces")
+    randnum = random.randint(0, 7)
+    # Shutdown interface
+    dut = "r2"
+    step(
+        " interface which is about to be shut no shut between r1 and r2 is " "%s",
+        topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"],
+    )
+    intf = topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"]
+    shutdown_bringup_interface(tgen, dut, intf, False)
+
+    step("Random no shut of the nexthop interfaces")
+    # Bringup interface
+    shutdown_bringup_interface(tgen, dut, intf, True)
+
+    step(
+        "After random shut/no shut of nexthop , only that "
+        "nexthop deleted/added from all the routes , other nexthop remain "
+        "unchanged"
+    )
+    dut = "r2"
+    protocol = "static"
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                    }
+                ]
+            }
+        }
+    result = verify_rib(
+        tgen,
+        addr_type,
+        dut,
+        input_dict_4,
+        next_hop=nh_all[addr_type],
+        protocol=protocol,
+    )
+    assert result is True, "Testcase {} : Failed \nError: Routes are"
+    " missing in RIB".format(tc_name)
+
+    step("Remove random static route with all the nexthop")
+    dut = "r2"
+    randnum = random.randint(1, 7)
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum)][addr_type],
+                        "delete": True,
+                    }
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "After delete of random route , that route only got deleted from"
+            " RIB/FIB other route are showing properly"
+        )
+        nh = NEXT_HOP_IP["nh{}".format(randnum)][addr_type]
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum)][addr_type],
+                    }
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step("Reload the FRR router")
+    # stop/start -> restart FRR router and verify
+    stop_router(tgen, "r2")
+    start_router(tgen, "r2")
+
+    step(
+        "After reload of FRR router , static route "
+        "installed in RIB and FIB properly ."
+    )
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        nhp = 1
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                    }
+                ]
+            }
+        }
+        logger.info("Verifying %s routes on r2", addr_type)
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh_all[addr_type],
+            protocol=protocol,
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+    step("Remove the redistribute static knob")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "redistribute": [
+                                    {"redist_type": "static", "delete": True}
+                                ]
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "After removing the BGP neighbor or redistribute static knob , "
+            "verify route got clear from RIB and FIB of R3 routes "
+        )
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " still present in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ebgp(request):
+    """
+    Verify static route functionality with 8 next hop different AD
+    value and BGP ECMP
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    step("Configure 8 interfaces / links between R1 and R2 ,")
+    step("Configure 8 interlaces/links between R2 and R3")
+    step(
+        "Configure IBGP IPv4 peering over loopback interface between"
+        "R2 and R3 router."
+    )
+    step("Configure redistribute static in BGP on R2 router")
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+    nh_all = {}
+    for addr_type in ADDR_TYPES:
+        nh_all[addr_type] = []
+        for nhp in range(1, 9):
+            nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+    step(
+        "Configure IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+        "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+        "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop"
+        "present on R1"
+    )
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+
+        step(
+            "On R2, static route installed in RIB using "
+            "show ip route with 8 next hop , lowest AD nexthop is active"
+        )
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+            wait=2,
+            attempts=3,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " are missing in RIB".format(tc_name)
+
+    step(
+        "Remove the static route configured with nexthop N1 to N8, one"
+        "by one from running config"
+    )
+
+    for addr_type in ADDR_TYPES:
+        # delete static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "After removing the static route with N1 to N8 one by one , "
+        "route become active with next preferred nexthop and nexthop which "
+        "got removed is not shown in RIB and FIB"
+    )
+    result = verify_rib(
+        tgen,
+        addr_type,
+        dut,
+        input_dict_4,
+        next_hop=nh_all[addr_type],
+        protocol=protocol,
+        expected=False,
+    )
+    assert result is not True, "Testcase {} : Failed \nError: Routes are"
+    " still present in RIB".format(tc_name)
+
+    step("Configure the static route with nexthop N1 to N8, one by one")
+
+    for addr_type in ADDR_TYPES:
+        # add static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        " After configuring them, route is always active with lowest AD"
+        " value and all the nexthop populated in RIB and FIB again"
+    )
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+            wait=2,
+            attempts=3,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " are missing in RIB".format(tc_name)
+
+    step("Random shut of the nexthop interfaces")
+    randnum = random.randint(0, 7)
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        input_dict_5 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+                    }
+                ]
+            }
+        }
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_5,
+            next_hop=nhip,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \n"
+        "Error: Routes are still present in RIB".format(tc_name)
+
+    step("Random no shut of the nexthop interfaces")
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \n"
+        "Error: Routes are missing in RIB".format(tc_name)
+
+    dut = "r2"
+    protocol = "static"
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert (
+            result is True
+        ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name)
+
+    protocol = "bgp"
+    dut = "r3"
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert (
+            result is True
+        ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name)
+
+    step("Reload the FRR router")
+    # stop/start -> restart FRR router and verify
+    stop_router(tgen, "r2")
+
+    start_router(tgen, "r2")
+
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert result is True, (
+            "Testcase {} : Failed \n"
+            "Error: Routes are still present in RIB".format(tc_name)
+        )
+
+
+    write_test_footer(tc_name)
+
+
+def test_static_route_8nh_diff_AD_ebgp_ecmp_p1_tc8_ebgp(request):
+    """
+    Verify static route with 8 next hop with different AD value and 8
+    EBGP neighbors
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    step("Configure 8 interfaces / links between R1 and R2")
+    step("Configure 8 interlaces/links between R2 and R3")
+    step("Configure 8 EBGP IPv4 peering between R2 and R3")
+
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+
+    step("Configure redistribute static in BGP on R2 router")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "Configure IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+        "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+        "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop"
+        "present on R1"
+    )
+    nh_all = {}
+    for addr_type in ADDR_TYPES:
+        nh_all[addr_type] = []
+        for nhp in range(1, 9):
+            nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+
+        step(
+            "On R2, static route installed in RIB using "
+            "show ip route with 8 next hop , lowest AD nexthop is active"
+        )
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " are missing in RIB".format(tc_name)
+
+    step(
+        "Remove the static route configured with nexthop N1 to N8, one"
+        "by one from running config"
+    )
+
+    for addr_type in ADDR_TYPES:
+        # delete static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "After removing the static route with N1 to N8 one by one , "
+        "route become active with next preferred nexthop and nexthop which "
+        "got removed is not shown in RIB and FIB"
+    )
+    result = verify_rib(
+        tgen,
+        addr_type,
+        dut,
+        input_dict_4,
+        next_hop=nh_all[addr_type],
+        protocol=protocol,
+        expected=False,
+    )
+    assert result is not True, "Testcase {} : Failed \nError: Routes are"
+    " still present in RIB".format(tc_name)
+
+    step("Configure the static route with nexthop N1 to N8, one by one")
+
+    for addr_type in ADDR_TYPES:
+        # add static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        " After configuring them, route is always active with lowest AD"
+        " value and all the nexthop populated in RIB and FIB again"
+    )
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " are missing in RIB".format(tc_name)
+
+    step("Random shut of the nexthop interfaces")
+    randnum = random.randint(0, 7)
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        input_dict_5 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+                    }
+                ]
+            }
+        }
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_5,
+            next_hop=nhip,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \n"
+        "Error: Routes are still present in RIB".format(tc_name)
+
+    step("Random no shut of the nexthop interfaces")
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \n"
+        "Error: Routes are missing in RIB".format(tc_name)
+
+    dut = "r2"
+    protocol = "static"
+
+    step("Reload the FRR router")
+    # stop/start -> restart FRR router and verify
+    stop_router(tgen, "r2")
+
+    start_router(tgen, "r2")
+
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert result is True, (
+            "Testcase {} : Failed \n"
+            "Error: Routes are still present in RIB".format(tc_name)
+        )
+
+    write_test_footer(tc_name)
+
+
+def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc10_ebgp(request):
+    """
+    Verify 8 static route functionality with 8 next hop different AD'
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    NEXT_HOP_IP = populate_nh()
+
+    step("Configure 8 interfaces / links between R1 and R2 ")
+    step("Configure 8 IBGP IPv4 peering between R2 and R3 router.")
+    reset_config_on_routers(tgen)
+
+    step(
+        "Configure IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+        "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+        "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80"
+    )
+    step(
+        "Configure nexthop AD in such way for static route S1 , N1 is"
+        "preferred and for S2 , N2 is preferred and so on .."
+    )
+    nh_all = {}
+    for addr_type in ADDR_TYPES:
+        nh_all[addr_type] = []
+        for nhp in range(1, 9):
+            nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+            second_rte = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX2[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, second_rte)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+
+        step(
+            "On R2, static route installed in RIB using "
+            "show ip route with 8 next hop , lowest AD nexthop is active"
+        )
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+        step("Verify that highest AD nexthop are inactive")
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+            wait=2,
+            attempts=3,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " are missing in RIB".format(tc_name)
+
+    step("Configure redistribute static in BGP on R2 router")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "Remove the static route configured with nexthop N1 to N8, one"
+        "by one from running config"
+    )
+
+    for addr_type in ADDR_TYPES:
+        # delete static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "After removing the static route with N1 to N8 one by one , "
+            "route become active with next preferred nexthop and nexthop which"
+            "got removed is not shown in RIB and FIB"
+        )
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " still present in RIB".format(tc_name)
+
+    step("Configure the static route with nexthop N1 to N8, one by one")
+    for addr_type in ADDR_TYPES:
+        # add static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        " After configuring them, route is always active with lowest AD"
+        " value and all the nexthop populated in RIB and FIB again"
+    )
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}}
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        "lowest AD  is missing in RIB".format(tc_name)
+
+    step("Random shut of the nexthop interfaces")
+    randnum = random.randint(0, 7)
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        input_dict_5 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+                    }
+                ]
+            }
+        }
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_5,
+            next_hop=nhip,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \n"
+        "Error: Routes are still present in RIB".format(tc_name)
+
+    step("Random no shut of the nexthop interfaces")
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \n"
+        "Error: Routes are missing in RIB".format(tc_name)
+
+    step("Remove random static route with all the nexthop")
+    for addr_type in ADDR_TYPES:
+        # delete static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+
+            step(
+                "After removing the static route with N1 to N8 one by one , "
+                "route become active with next preferred nexthop and nexthop "
+                "which got removed is not shown in RIB and FIB"
+            )
+            nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type]
+            result = verify_rib(
+                tgen,
+                addr_type,
+                dut,
+                input_dict_4,
+                next_hop=nh,
+                protocol=protocol,
+                expected=False,
+            )
+            assert result is not True, "Testcase {} : Failed \nError: Route "
+            " is still present in RIB".format(tc_name)
+
+        step("Reconfigure the deleted routes and verify they are installed")
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+
+            dut = "r2"
+            protocol = "static"
+            nh = NEXT_HOP_IP["nh1"][addr_type]
+            result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+            assert result is True, "Testcase {} : Failed \nError: Route "
+            " is still present in RIB".format(tc_name)
+
+            step("Reload the FRR router")
+            # stop/start -> restart FRR router and verify
+            stop_router(tgen, "r2")
+
+            start_router(tgen, "r2")
+
+            step("After reloading, verify that routes are still present in R2.")
+            result = verify_rib(
+                tgen,
+                addr_type,
+                dut,
+                second_rte,
+                next_hop=nh,
+                protocol=protocol,
+                fib=True,
+            )
+            assert result is True, (
+                "Testcase {} : Failed \nError: Route "
+                " is missing in RIB".format(tc_name)
+            )
+
+    write_test_footer(tc_name)
+
+
+def test_static_route_delete_p0_tc11_ebgp(request):
+    """
+    Delete the static route and verify the RIB and FIB state
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    NEXT_HOP_IP = populate_nh()
+
+    step("Configure 8 interfaces / links between R1 and R2 ")
+    step("Configure 8 IBGP IPv4 peering between R2 and R3 router.")
+    reset_config_on_routers(tgen)
+
+    step(
+        "Configure IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+        "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+        "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80"
+    )
+    step(
+        "Configure nexthop AD in such way for static route S1 , N1 is"
+        "preferred and for S2 , N2 is preferred and so on .."
+    )
+    nh_all = {}
+    for addr_type in ADDR_TYPES:
+        nh_all[addr_type] = []
+        for nhp in range(1, 9):
+            nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+            second_rte = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX2[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, second_rte)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+
+        step(
+            "On R2, static route installed in RIB using "
+            "show ip route with 8 next hop , lowest AD nexthop is active"
+        )
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+        step("Verify that highest AD nexthop are inactive")
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " are missing in RIB".format(tc_name)
+
+    step("Configure redistribute static in BGP on R2 router")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step("Remove the redistribute static knob")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "redistribute": [
+                                    {"redist_type": "static", "delete": True}
+                                ]
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "Verify after removing the redistribute static from BGP all the"
+            "routes got delete from RIB and FIB of R3 "
+        )
+
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " still present in RIB".format(tc_name)
+
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+            second_rte = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX2[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, second_rte)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+
+        step(
+            " After removing all the routes and nexthop from R2 , "
+            " verify R2 RIB and FIB is cleared"
+        )
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " still active in RIB".format(tc_name)
+    write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py
new file mode 100644 (file)
index 0000000..255bb07
--- /dev/null
@@ -0,0 +1,1333 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+"""
+    -Verify static route ECMP functionality with 8 next hop
+
+    -Verify static route functionality with 8 next hop different AD value
+
+    -Verify static route with tag option
+
+    -Verify BGP did not install the static route when it receive route
+    with local next hop
+
+"""
+import sys
+import json
+import time
+import os
+import pytest
+import random
+import platform
+from lib.topotest import version_cmp
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+from lib.common_config import (
+    start_topology,
+    write_test_header,
+    write_test_footer,
+    reset_config_on_routers,
+    verify_rib,
+    create_static_routes,
+    check_address_types,
+    step,
+    create_interfaces_cfg,
+    shutdown_bringup_interface,
+    stop_router,
+    start_router,
+    create_route_maps,
+    verify_ip_nht,
+)
+from lib.topolog import logger
+from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo3_ebgp.json".format(CWD)
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {
+    "ipv4": [
+        "11.0.20.1/32",
+        "11.0.20.2/32",
+        "11.0.20.3/32",
+        "11.0.20.4/32",
+        "11.0.20.5/32",
+        "11.0.20.6/32",
+        "11.0.20.7/32",
+        "11.0.20.8/32",
+    ],
+    "ipv6": [
+        "2::1/128",
+        "2::2/128",
+        "2::3/128",
+        "2::4/128",
+        "2::5/128",
+        "2::6/128",
+        "2::7/128",
+        "2::8/128",
+    ],
+}
+PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"}
+NETWORK2 = {"ipv4": ["11.0.20.1/32"], "ipv6": ["2::1/128"]}
+NEXT_HOP_IP = []
+
+
+class CreateTopo(Topo):
+    """
+    Test CreateTopo - topology 1.
+
+    * `Topo`: Topology object
+    """
+
+    def build(self, *_args, **_opts):
+        """Build function."""
+        tgen = get_topogen(self)
+
+        # Building topology from json file
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    """
+
+    Set up the pytest environment.
+
+    * `mod`: module name
+    """
+    global topo
+    testsuite_run_time = time.asctime(time.localtime(time.time()))
+    logger.info("Testsuite start time: {}".format(testsuite_run_time))
+    logger.info("=" * 40)
+
+    logger.info("Running setup_module to create topology")
+
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(CreateTopo, mod.__name__)
+    # ... and here it calls Mininet initialization functions.
+
+    # Starting topology, create tmp files which are loaded to routers
+    #  to start deamons and then start routers
+    start_topology(tgen)
+
+    # Creating configuration from JSON
+    build_config_from_json(tgen, topo)
+
+    if version_cmp(platform.release(), "4.19") < 0:
+        error_msg = (
+            'These tests will not run. (have kernel "{}", '
+            "requires kernel >= 4.19)".format(platform.release())
+        )
+        pytest.skip(error_msg)
+
+    # Checking BGP convergence
+    global BGP_CONVERGENCE
+    global ADDR_TYPES
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    # Api call verify whether BGP is converged
+    BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+    assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+        BGP_CONVERGENCE
+    )
+
+    logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+    """
+    Teardown the pytest environment
+
+    * `mod`: module name
+    """
+
+    logger.info("Running teardown_module to delete topology")
+
+    tgen = get_topogen()
+
+    # Stop toplogy and Remove tmp files
+    tgen.stop_topology()
+
+    logger.info(
+        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+    )
+    logger.info("=" * 40)
+
+
+def populate_nh():
+    NEXT_HOP_IP = {
+        "nh1": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0],
+        },
+        "nh2": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0],
+        },
+        "nh3": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0],
+        },
+        "nh4": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link3"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link3"]["ipv6"].split("/")[0],
+        },
+        "nh5": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link4"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link4"]["ipv6"].split("/")[0],
+        },
+        "nh6": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link5"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link5"]["ipv6"].split("/")[0],
+        },
+        "nh7": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link6"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link6"]["ipv6"].split("/")[0],
+        },
+        "nh8": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link7"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link7"]["ipv6"].split("/")[0],
+        },
+    }
+    return NEXT_HOP_IP
+
+
+#####################################################
+#
+#   Tests starting
+#
+#####################################################
+
+
+def test_staticroute_with_ecmp_p0_tc3_ebgp(request):
+    """
+    Verify static route ECMP functionality with 8 next hop'
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+
+    step("Configure 8 interfaces / links between R1 and R2,")
+    step(
+        "Configure IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2), N2(22.1.1.2), N3(23.1.1.2), N4(24.1.1.2),"
+        "N5(25.1.1.2), N6(26.1.1.2), N7(27.1.1.2),N8(28.1.1.2), Static"
+        "route next-hop present on R1"
+    )
+
+    step("Configure IBGP IPv4 peering between R2 and R3 router.")
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+        nh = [
+            NEXT_HOP_IP["nh1"][addr_type],
+            NEXT_HOP_IP["nh2"][addr_type],
+            NEXT_HOP_IP["nh3"][addr_type],
+            NEXT_HOP_IP["nh4"][addr_type],
+            NEXT_HOP_IP["nh5"][addr_type],
+            NEXT_HOP_IP["nh6"][addr_type],
+            NEXT_HOP_IP["nh7"][addr_type],
+            NEXT_HOP_IP["nh8"][addr_type],
+        ]
+
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+    step("Configure redistribute static in BGP on R2 router")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "Remove the static route configured with nexthop N1 to N8, one"
+        "by one from running config"
+    )
+    for addr_type in ADDR_TYPES:
+        # delete static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " still present in RIB".format(tc_name)
+
+    step("Configure the static route with nexthop N1 to N8, one by" "one")
+
+    for addr_type in ADDR_TYPES:
+        # add static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    result = verify_rib(
+        tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+    )
+    assert result is True, "Testcase {} : Failed \nError: Routes are"
+    " missing in RIB".format(tc_name)
+
+    step("Random shut of the nexthop interfaces")
+    randnum = random.randint(0, 7)
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        input_dict_5 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+                    }
+                ]
+            }
+        }
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_5,
+            next_hop=nhip,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \n"
+        "Error: Routes are still present in RIB".format(tc_name)
+
+    step("Random no shut of the nexthop interfaces")
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \n"
+        "Error: Routes are missing in RIB".format(tc_name)
+
+    step("Reload the FRR router")
+    # stop/start -> restart FRR router and verify
+    stop_router(tgen, "r2")
+    start_router(tgen, "r2")
+
+    result = verify_rib(
+        tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+    )
+    assert result is True, "Testcase {} : Failed \nError: Routes are"
+    " missing in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_staticroute_with_ecmp_with_diff_AD_p0_tc4_ebgp(request):
+    """
+    Verify static route ECMP functionality with 8 next hop
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+
+    step("Configure 8 interfaces / links between R1 and R2,")
+    step("Configure IBGP IPv4 peering between R2 and R3 router.")
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+    nh_all = {}
+    for addr_type in ADDR_TYPES:
+        nh_all[addr_type] = []
+        for nhp in range(1, 9):
+            nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+    step(
+        "Configure IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+        "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+        "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop"
+        "present on R1"
+    )
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+
+        step(
+            "On R2, static route installed in RIB using "
+            "show ip route with 8 next hop, lowest AD nexthop is active"
+        )
+        step("On R2, static route with lowest AD nexthop installed in FIB")
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        " lowest AD is missing in RIB".format(tc_name)
+
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " with high AD are active in RIB".format(tc_name)
+
+    step("Configure redistribute static in BGP on R2 router")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+
+        logger.info("Configuring redistribute static")
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "After configuring them, route is always active with lowest AD"
+            "value and all the nexthop populated in RIB and FIB again "
+        )
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        " lowest AD is missing in RIB".format(tc_name)
+
+    step(
+        "Remove the static route configured with nexthop N1 to N8, one"
+        "by one from running config"
+    )
+
+    for addr_type in ADDR_TYPES:
+        # delete static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "After removing the static route with N1 to N8 one by one, "
+        "route become active with next preferred nexthop and nexthop which "
+        "got removed is not shown in RIB and FIB"
+    )
+    result = verify_rib(
+        tgen,
+        addr_type,
+        dut,
+        input_dict_4,
+        next_hop=nh_all[addr_type],
+        protocol=protocol,
+        expected=False,
+    )
+    assert result is not True, "Testcase {} : Failed \nError: Routes are"
+    " still present in RIB".format(tc_name)
+
+    step("Configure the static route with nexthop N1 to N8, one by" "one")
+    for addr_type in ADDR_TYPES:
+        # add static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("On R2, static route with lowest AD nexthop installed in FIB")
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        " lowest AD is missing in RIB".format(tc_name)
+
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " with high AD are active in RIB".format(tc_name)
+
+    step("Random shut of the nexthop interfaces")
+    randnum = random.randint(0, 7)
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        input_dict_5 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+                    }
+                ]
+            }
+        }
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_5,
+            next_hop=nhip,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \n"
+        "Error: Routes are still present in RIB".format(tc_name)
+
+    step("Random no shut of the nexthop interfaces")
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \n"
+        "Error: Routes are missing in RIB".format(tc_name)
+
+    step("Reload the FRR router")
+    # stop/start -> restart FRR router and verify
+    stop_router(tgen, "r2")
+    start_router(tgen, "r2")
+
+    step(
+        "After reload of FRR router, static route installed "
+        "in RIB and FIB properly ."
+    )
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        " lowest AD is missing in RIB".format(tc_name)
+
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " with high AD are active in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_bgp_local_nexthop_p1_tc14_ebgp(request):
+    """
+    Verify BGP did not install the static route when it receive route
+    with local next hop
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    step("Configure BGP IPv4 session between R2 and R3")
+    step("Configure IPv4 static route on R2")
+    reset_config_on_routers(tgen)
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": topo["routers"]["r3"]["links"]["r2-link0"][
+                            addr_type
+                        ].split("/")[0],
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Configure redistribute static in the BGP")
+
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Verify R2 BGP table has IPv4 route")
+        dut = "r2"
+        result = verify_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB of R2".format(tc_name)
+
+        step(" Verify route did not install in the R3 BGP table, RIB/FIB")
+        dut = "r3"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4, expected=False)
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in BGP RIB of R2".format(tc_name)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, expected=False)
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB of R2".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_frr_intf_name_as_gw_gap_tc4_ebgp_p0(request):
+    """
+    Verify static route configure with interface name as gateway'
+        'address'
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    reset_config_on_routers(tgen)
+
+    dut = "r1"
+    intf = topo["routers"]["r1"]["links"]["r2-link0"]["interface"]
+    nh = topo["routers"]["r1"]["links"]["r2-link0"]
+    ip_list = {
+        "ipv4": [(dut, intf, ["1.1.1.1/32"], nh["ipv4"].split("/")[0])],
+        "ipv6": [(dut, intf, ["4001::32/128"], nh["ipv6"].split("/")[0])],
+    }
+
+    step(
+        "Configure IPv4 and IPv6 static route in FRR with different next"
+        "hop (ens224 as nexthop))"
+    )
+    step("ip route 2.2.2.0/24 20.1.1.1 ens224 ----from FRR cli")
+    step("ipv6 route 2000::1/120 5000::1 ens224 ----from FRR cli")
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        nh = topo["routers"]["r2"]["links"]["r1-link0"][addr_type].split("/")[0]
+        input_dict_4 = {
+            "r1": {
+                "static_routes": [
+                    {"network": ip_list[addr_type][0][2][0], "next_hop": nh}
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "IPv4 and IPv6 Static route added in FRR verify using "
+            "show ip route , nexthop is resolved using show nht"
+        )
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, next_hop=nh
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        input_dict_nh = {
+            "r1": {
+                nh: {
+                    "Address": nh,
+                    "resolvedVia": "connected",
+                    "nexthops": {"nexthop1": {"Interfcae": intf}},
+                }
+            }
+        }
+        result = verify_ip_nht(tgen, input_dict_nh)
+        assert result is True, "Testcase {} : Failed \nError: Nexthop is"
+        " missing in RIB".format(tc_name)
+
+        step(
+            "Shut / no shut IPv4 and IPv6 static next hop interface from"
+            "kernel and FRR CLI"
+        )
+
+        shutdown_bringup_interface(tgen, dut, intf, False)
+
+        step(
+            "After shut of nexthop interface, IPv4 and IPv6 route got removed "
+            "from RIB verify using show ip route show nht"
+        )
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            protocol=protocol,
+            next_hop=nh,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        shutdown_bringup_interface(tgen, dut, intf, True)
+
+        step(
+            "After no shut route got added again in RIB /FIB using "
+            "show ip route nexthop is resolved using show nht"
+        )
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert result is True, "Testcase {} : Failed".format(tc_name)
+
+    for addr_type in ADDR_TYPES:
+        nh = topo["routers"]["r2"]["links"]["r1-link0"][addr_type].split("/")[0]
+        input_dict_4 = {
+            "r1": {
+                "static_routes": [
+                    {
+                        "network": ip_list[addr_type][0][2][0],
+                        "next_hop": nh,
+                        "delete": True,
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "Removing FRR configured static route verify FRR route also "
+            "removed from FRR"
+        )
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            protocol=protocol,
+            next_hop=nh,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes"
+        " still present in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_static_route_with_tag_p0_tc_13_ebgp(request):
+    """
+    Verify static route with tag option
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    step("Configure 8 links between R1 and R2")
+    step("Configure 1 links between R2 and R3")
+    NEXT_HOP_IP = populate_nh()
+
+    step(
+        "Configure 2 IPv4 static route (S1 and S2) in R2 with same"
+        "next hop N1 28.1.1.2"
+    )
+    step("Configure static route S1 with tag 1 and static route S2 with" "tag2")
+    step("S1= ip route 10.1.1.1/24 28.1.1.2 tag 1")
+    step("S2= ip route 20.1.1.1/24 28.1.1.2 tag 2")
+    step("Enable redistribute static in BGP with route-map")
+    reset_config_on_routers(tgen)
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "tag": 4001,
+                    },
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "tag": 4002,
+                    },
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+        step("verify routes are present in RIB")
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+        step("Configure route-map on R2 with allow tag1 and deny tag2")
+
+        # Create route map
+        input_dict_3 = {
+            "r2": {
+                "route_maps": {
+                    "rmap_match_tag_1_{}".format(addr_type): [
+                        {
+                            "action": "permit",
+                            "seq_id": 10,
+                            "match": {addr_type: {"tag": "4001"}},
+                        },
+                        {
+                            "action": "deny",
+                            "seq_id": 20,
+                            "match": {addr_type: {"tag": "4002"}},
+                        },
+                    ]
+                }
+            }
+        }
+        result = create_route_maps(tgen, input_dict_3)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        # Configure neighbor for route map
+        input_dict_4 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "r2-link0": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_match_tag_1_ipv4",
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                },
+                                "redistribute": [{"redist_type": "static"}],
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "Verify static route S1 advetised in BGP table when tag1 permit"
+            "in route-map else it is denied"
+        )
+        dut = "r3"
+        input_dict_0 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "tag": 4002,
+                    }
+                ]
+            }
+        }
+
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_0, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route with "
+        "tag 4002 is still present in RIB".format(tc_name)
+
+        dut = "r2"
+        input_dict_1 = {
+            "r2": {"static_routes": [{"network": NETWORK[addr_type], "tag": 4001}]}
+        }
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_0, protocol=protocol)
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        "tag 4001 is missing in RIB".format(tc_name)
+
+        step("Modify the route-map to allow tag2 and deny tag1")
+        # Create route map
+        input_dict_3 = {
+            "r2": {
+                "route_maps": {
+                    "rmap_match_tag_1_{}".format(addr_type): [
+                        {
+                            "action": "deny",
+                            "seq_id": 10,
+                            "match": {addr_type: {"tag": "4001"}},
+                        },
+                        {
+                            "action": "permit",
+                            "seq_id": 20,
+                            "match": {addr_type: {"tag": "4002"}},
+                        },
+                    ]
+                }
+            }
+        }
+        result = create_route_maps(tgen, input_dict_3)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        dut = "r3"
+        step(
+            "Verify static route S2 advertised in BGP table when tag2"
+            "permit in route-map else it is denied"
+        )
+        protocol = "bgp"
+        input_dict_0 = {
+            "r2": {"static_routes": [{"network": NETWORK2[addr_type], "tag": 4002}]}
+        }
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_0, protocol=protocol)
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        "tag 4002 is missing in RIB".format(tc_name)
+
+        input_dict_1 = {
+            "r2": {"static_routes": [{"network": NETWORK[addr_type], "tag": 4001}]}
+        }
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_1, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route with "
+        "tag 4001 is still present in RIB".format(tc_name, result)
+
+    step("Configure one static route with 2 ECMP nexthop N1 and N2")
+    step("For N1 configure tag 1 and for N2 configure tag 2")
+    step("S1= ip route 10.1.1.1/24 28.1.1.2 tag 1")
+    step("S1= ip route 10.1.1.1/24 29.1.1.2 tag 2")
+    step("configure the route-map to allow tag1 and deny tag 2")
+    step("Modify the route-map to allow tag2 and deny tag1")
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "tag": 4001,
+                    },
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "tag": 4002,
+                    },
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+    step("shut/no shut of tag1 and tag2 nexthop")
+
+    intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"]
+    shutdown_bringup_interface(tgen, dut, intf, False)
+
+    shutdown_bringup_interface(tgen, dut, intf, True)
+
+    step("configure one static route with 3 next-hop")
+    step("N1-tag1, N2-tag2, N3-tag3")
+    step("S1= ip route 10.1.1.1/24 28.1.1.2 tag 1")
+    step("S1= ip route 10.1.1.1/24 29.1.1.2 tag 2")
+    step("S1= ip route 10.1.1.1/24 28.1.1.2 tag 3")
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "tag": 4001,
+                    },
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "tag": 4002,
+                    },
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh3"][addr_type],
+                        "tag": 4003,
+                    },
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+
+        step("configure the route-map to allow tag2 & tag3 and deny tag1")
+        # Create route map
+        input_dict_3 = {
+            "r2": {
+                "route_maps": {
+                    "rmap_match_tag_1_{}".format(addr_type): [
+                        {
+                            "action": "deny",
+                            "seq_id": 10,
+                            "match": {addr_type: {"tag": "4001"}},
+                        },
+                        {
+                            "action": "permit",
+                            "seq_id": 20,
+                            "match": {addr_type: {"tag": "4002"}},
+                        },
+                        {
+                            "action": "permit",
+                            "seq_id": 30,
+                            "match": {addr_type: {"tag": "4003"}},
+                        },
+                    ]
+                }
+            }
+        }
+        result = create_route_maps(tgen, input_dict_3)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "Verify static route advertised in BGP table with tag3"
+            " nexthop if tag2 is down"
+        )
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("shut / no shut of tag2 and tag3 next-hop")
+
+        intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+
+        intf = topo["routers"]["r2"]["links"]["r1-link2"]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+
+        step("shut/no shut of tag2 and tag3 nexthop")
+        intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+
+        intf = topo["routers"]["r2"]["links"]["r1-link2"]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+
+        step("Verify after shut/noshut of nexthop BGP table updated correctly")
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py
new file mode 100644 (file)
index 0000000..75657a8
--- /dev/null
@@ -0,0 +1,994 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+
+Following tests are covered in the script.
+
+- Verify static route are blocked from route-map and prefix-list
+    applied in BGP nbrs
+- Verify Static route when FRR connected to 2 TOR
+"""
+
+import sys
+import json
+import time
+import os
+import pytest
+import platform
+import ipaddress
+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 mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+    start_topology,
+    write_test_header,
+    write_test_footer,
+    reset_config_on_routers,
+    verify_rib,
+    check_address_types,
+    step,
+    create_prefix_lists,
+    create_route_maps,
+    create_interfaces_cfg,
+    verify_prefix_lists,
+    verify_route_maps,
+)
+from lib.topolog import logger
+from lib.bgp import (
+    verify_bgp_convergence,
+    create_router_bgp,
+    clear_bgp_and_verify,
+    clear_bgp,
+)
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo4_ebgp.json".format(CWD)
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {"ipv4": "2.2.2.2/32", "ipv6": "22:22::2/128"}
+NEXT_HOP_IP = {}
+
+
+class CreateTopo(Topo):
+    """
+    Test CreateTopo - topology 1.
+
+    * `Topo`: Topology object
+    """
+
+    def build(self, *_args, **_opts):
+        """Build function."""
+        tgen = get_topogen(self)
+
+        # Building topology from json file
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    """
+    Set up the pytest environment.
+    * `mod`: module name
+    """
+    global topo
+    testsuite_run_time = time.asctime(time.localtime(time.time()))
+    logger.info("Testsuite start time: {}".format(testsuite_run_time))
+    logger.info("=" * 40)
+
+    logger.info("Running setup_module to create topology")
+
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(CreateTopo, mod.__name__)
+    # ... and here it calls Mininet initialization functions.
+
+    # Starting topology, create tmp files which are loaded to routers
+    #  to start deamons and then start routers
+    start_topology(tgen)
+
+    # Creating configuration from JSON
+    build_config_from_json(tgen, topo)
+
+    if version_cmp(platform.release(), '4.19') < 0:
+        error_msg = ('These tests will not run. (have kernel "{}", '
+            'requires kernel >= 4.19)'.format(platform.release()))
+        pytest.skip(error_msg)
+
+    # Checking BGP convergence
+    global BGP_CONVERGENCE
+    global ADDR_TYPES
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    # Api call verify whether BGP is converged
+    BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+    assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+        BGP_CONVERGENCE
+    )
+
+    logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+    """
+    Teardown the pytest environment.
+
+    * `mod`: module name
+    """
+    logger.info("Running teardown_module to delete topology")
+
+    tgen = get_topogen()
+
+    # Stop toplogy and Remove tmp files
+    tgen.stop_topology()
+
+    logger.info(
+        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+    )
+    logger.info("=" * 40)
+
+
+#####################################################
+#
+#   Tests starting
+#
+#####################################################
+def static_routes_rmap_pfxlist_p0_tc7_ebgp(request):
+    """
+    Verify static route are blocked from route-map & prefix-list applied in BGP
+    nbrs
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    reset_config_on_routers(tgen)
+    step("Configure holddown timer = 1 keep alive = 3 in all the neighbors")
+    step("verify bgp convergence before starting test case")
+
+    bgp_convergence = verify_bgp_convergence(tgen, topo)
+    assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, bgp_convergence
+    )
+
+    step(
+        "Configure 4 IPv4 and 4 IPv6 nbrs with password with mismatch "
+        " authentication between FRR routers "
+    )
+
+    for addr_type in ADDR_TYPES:
+        # Api call to modfiy BGP timerse
+        input_dict = {
+            "r2": {
+                "bgp": {
+                    "local_as": "200",
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r1": {
+                                        "dest_link": {
+                                            "r2-link0": {"password": "r2"},
+                                            "r2-link1": {"password": "r2"},
+                                            "r2-link2": {"password": "r2"},
+                                            "r2-link3": {"password": "r2"},
+                                        }
+                                    },
+                                    "r3": {
+                                        "dest_link": {
+                                            "r2-link0": {"password": "r2"},
+                                            "r2-link1": {"password": "r2"},
+                                            "r2-link2": {"password": "r2"},
+                                            "r2-link3": {"password": "r2"},
+                                        }
+                                    },
+                                }
+                            }
+                        }
+                    },
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict)
+        assert result is True, "Testcase {} :Failed \n Error: {}".format(
+            tc_name, result
+        )
+        clear_bgp(tgen, addr_type, "r2")
+
+    step(" All BGP nbrs are down as authentication is mismatch on both" " the sides")
+
+    bgp_convergence = verify_bgp_convergence(tgen, topo, expected=False)
+    assert bgp_convergence is not True, "Testcase {} : "
+    "Failed \n BGP nbrs must be down. Error: {}".format(tc_name, bgp_convergence)
+
+    step(
+        "Configure 4 IPv4 and 4 IPv6 nbrs with macthing password  "
+        " authentication between FRR routers "
+    )
+    for addr_type in ADDR_TYPES:
+        input_dict = {
+            "r2": {
+                "bgp": {
+                    "local_as": "200",
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r1": {
+                                        "dest_link": {
+                                            "r2-link0": {"password": "r1"},
+                                            "r2-link1": {"password": "r1"},
+                                            "r2-link2": {"password": "r1"},
+                                            "r2-link3": {"password": "r1"},
+                                        }
+                                    },
+                                    "r3": {
+                                        "dest_link": {
+                                            "r2-link0": {"password": "r1"},
+                                            "r2-link1": {"password": "r1"},
+                                            "r2-link2": {"password": "r1"},
+                                            "r2-link3": {"password": "r1"},
+                                        }
+                                    },
+                                }
+                            }
+                        }
+                    },
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, deepcopy(input_dict))
+        assert result is True, "Testcase {} :Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step("All BGP nbrs are up as authentication is matched now")
+    bgp_convergence = verify_bgp_convergence(tgen, topo)
+    assert bgp_convergence is True, "Testcase {} : Failed \n " "Error: {}".format(
+        tc_name, bgp_convergence
+    )
+
+    step("Create prefix list P1 to permit VM3 & deny VM1 v4 & v6 routes")
+    step("Create prefix list P2 to permit VM6 IPv4 and IPv6 routes")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "prefix_lists": {
+                    addr_type: {
+                        "pf_list_1_{}".format(addr_type): [
+                            {
+                                "seqid": 10,
+                                "network": topo["routers"]["r2"]["links"]["vm3"][
+                                    addr_type
+                                ],
+                                "action": "permit",
+                            },
+                            {
+                                "seqid": 20,
+                                "network": topo["routers"]["r2"]["links"]["vm1"][
+                                    addr_type
+                                ],
+                                "action": "deny",
+                            },
+                        ],
+                        "pf_list_2_{}".format(addr_type): [
+                            {
+                                "seqid": 10,
+                                "network": topo["routers"]["r2"]["links"]["vm6"][
+                                    addr_type
+                                ],
+                                "action": "permit",
+                            }
+                        ],
+                    }
+                }
+            }
+        }
+        result = create_prefix_lists(tgen, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "Prefix list created with matching networks deny or permit "
+            "show ip prefix list"
+        )
+        result = verify_prefix_lists(tgen, input_dict_2)
+        assert result is not True, "Testcase {} : Failed \n"
+        " Error: {}".format(tc_name, result)
+
+        step("Redistribute all the routes (connected, static)")
+        input_dict_2_r1 = {
+            "r1": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2_r1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        input_dict_2_r2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2_r2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        input_dict_2_r3 = {
+            "r3": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2_r3)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("configure redistribute connected in Router BGP")
+
+        input_dict_2_r1 = {
+            "r1": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "connected"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2_r1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        input_dict_2_r3 = {
+            "r3": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "connected"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2_r3)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "connected"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Apply prefix list P1 on BGP neighbors 1 2 3 4 connected from " "frr r1")
+        # Configure prefix list to bgp neighbor
+        input_dict_4 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r1": {
+                                        "dest_link": {
+                                            "r2-link0": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link1": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link2": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link3": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Apply prefix list P2 on BGP nbrs 5 & 6 connected from FRR-2")
+        # Configure prefix list to bgp neighbor
+        input_dict_4 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "r2-link0": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link1": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link2": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link3": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        clear_bgp_and_verify(tgen, topo, "r2")
+
+        step(
+            "VM1 IPv4 and IPv6 Route which is denied using prefix list is "
+            "not present on FRR1 side routing table , also not able to "
+            "ping the routes show ip route"
+        )
+
+        dut = "r1"
+        protocol = "bgp"
+        ntwk_r2_vm1 = str(
+            ipaddress.ip_interface(
+                u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type])
+            ).network
+        )
+        input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+        result4 = verify_rib(
+            tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
+        )
+        assert result4 is not True, "Testcase {} : Failed , VM1 route is "
+        "not filtered out via prefix list. \n Error: {}".format(tc_name, result4)
+
+        step(
+            "VM4 and VM6 IPV4 and IPv6 address are present in local and "
+            "FRR2 routing table show ip bgp show ip route"
+        )
+
+        dut = "r2"
+        ntwk_r2_vm6 = str(
+            ipaddress.ip_interface(
+                u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type])
+            ).network
+        )
+        input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}}
+        result4 = verify_rib(tgen, addr_type, dut, input_dict)
+        assert result4 is True, "Testcase {} : Failed.\n Error: {}".format(
+            tc_name, result4
+        )
+
+        step("Remove prefix list from all the neighbors")
+        input_dict_4 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r1": {
+                                        "dest_link": {
+                                            "r2-link0": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link1": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link2": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link3": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        input_dict_4 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "r2-link0": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link1": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link2": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link3": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        clear_bgp_and_verify(tgen, topo, "r2")
+
+        step("Create RouteMap_1 with prefix list P1 and weight 50")
+        # Create route map
+        rmap_dict = {
+            "r2": {
+                "route_maps": {
+                    "rmap_pf_list_1_{}".format(addr_type): [
+                        {
+                            "action": "permit",
+                            "set": {"weight": 50},
+                            "match": {
+                                addr_type: {
+                                    "prefix_lists": "pf_list_1_{}".format(addr_type)
+                                }
+                            },
+                        }
+                    ]
+                }
+            }
+        }
+        result = create_route_maps(tgen, rmap_dict)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Create RouteMap_2 with prefix list P2 and weight 50")
+        # Create route map
+        rmap_dict = {
+            "r2": {
+                "route_maps": {
+                    "rmap_pf_list_2_{}".format(addr_type): [
+                        {
+                            "action": "permit",
+                            "set": {"weight": 50},
+                            "match": {
+                                addr_type: {
+                                    "prefix_lists": "pf_list_2_{}".format(addr_type)
+                                }
+                            },
+                        }
+                    ]
+                }
+            }
+        }
+        result = create_route_maps(tgen, rmap_dict)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Verify Route-map created verify using show route-map")
+        # verify rmap_pf_list_1 and rmap_pf_list_2 are present in router r2
+        input_dict = {
+            "r2": {
+                "route_maps": [
+                    "rmap_pf_list_1_{}".format(addr_type),
+                    "rmap_pf_list_2_{}".format(addr_type),
+                ]
+            }
+        }
+        result = verify_route_maps(tgen, input_dict, expected=False)
+        assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Apply policy RouteMap_1 nbrs 1 2 3 4 to FRR 1")
+        # Configure prefix list to bgp neighbor
+        input_dict_4 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r1": {
+                                        "dest_link": {
+                                            "r2-link0": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_1_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link1": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_1_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link2": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_1_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link3": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_1_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Apply policy RouteMap_2 nbrs 5 and 6 to FRR2")
+        # Configure prefix list to bgp neighbor
+        input_dict_4 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "r2-link0": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_2_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link1": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_2_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link2": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_2_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link3": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_2_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "After applying to BGP neighbors verify VM1 IPv4 and IPv6 Route"
+            " which is denied using prefix list is not present on FRR side"
+            " routing table , also not able to ping the routes show ip route"
+            " and VM4 and VM6 IPV4 and IPv6 address are present in local and"
+            " FRR routing table show ip bgp show ip route"
+        )
+
+        dut = "r1"
+        protocol = "bgp"
+        ntwk_r2_vm1 = str(
+            ipaddress.ip_interface(
+                u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type])
+            ).network
+        )
+        input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+        result4 = verify_rib(
+            tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
+        )
+        assert result4 is not True, "Testcase {} : Failed \n" "Error: {}".format(
+            tc_name, result4
+        )
+
+        step("vm4 should be present in FRR1")
+        dut = "r1"
+        ntwk_r2_vm1 = str(
+            ipaddress.ip_interface(
+                u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type])
+            ).network
+        )
+        input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+        result4 = verify_rib(tgen, addr_type, dut, input_dict)
+        assert result4 is True, "Testcase {} : Failed , VM1 route is "
+        "not filtered out via prefix list. \n Error: {}".format(tc_name, result4)
+
+        step("vm4 should be present in FRR2")
+        dut = "r2"
+        ntwk_r2_vm1 = str(
+            ipaddress.ip_interface(
+                u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type])
+            ).network
+        )
+        input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+        result4 = verify_rib(tgen, addr_type, dut, input_dict)
+        assert result4 is True, "Testcase {} : Failed , VM1 route is "
+        "not filtered out via prefix list. \n Error: {}".format(tc_name, result4)
+
+        dut = "r3"
+        protocol = "bgp"
+        ntwk_r2_vm6 = str(
+            ipaddress.ip_interface(
+                u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type])
+            ).network
+        )
+        input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}}
+        result4 = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol)
+        assert result4 is True, "Testcase {} : Failed.\n Error: {}".format(
+            tc_name, result4
+        )
+
+    write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo1_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo1_ibgp.json
new file mode 100644 (file)
index 0000000..99b1973
--- /dev/null
@@ -0,0 +1,157 @@
+{
+    "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-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+                                    "dest_link": {
+                                        "r2": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+                                    "dest_link": {
+                                        "r2": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo2_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo2_ibgp.json
new file mode 100644 (file)
index 0000000..47596a0
--- /dev/null
@@ -0,0 +1,371 @@
+{
+    "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-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "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"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+
+
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link1": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link2": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link3": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link4": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link5": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link6": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link7": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            },
+                            "redistribute": [{
+                                "redist_type": "static"
+                            }]
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+
+
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link1": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link2": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link3": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link4": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link5": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link6": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r2-link7": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            },
+                            "redistribute": [{
+                                "redist_type": "static"
+                            }]
+                        }
+                    }
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+
+
+                                    "dest_link": {
+                                        "r3-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link1": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link2": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link3": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link4": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link5": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link6": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link7": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+
+
+                                    "dest_link": {
+                                        "r3-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link1": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link2": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link3": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link4": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link5": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link6": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        },
+                                        "r3-link7": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo3_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo3_ibgp.json
new file mode 100644 (file)
index 0000000..4e27229
--- /dev/null
@@ -0,0 +1,189 @@
+{
+    "address_types": [
+        "ipv4",
+        "ipv6"
+    ],
+    "ipv4base": "10.0.0.0",
+    "ipv4mask": 30,
+    "ipv6base": "fd00::",
+    "ipv6mask": 64,
+    "link_ip_start": {
+        "ipv4": "10.0.0.0",
+        "v4mask": 29,
+        "ipv6": "fd00::",
+        "v6mask": 64
+    },
+    "lo_prefix": {
+        "ipv4": "1.0.",
+        "v4mask": 32,
+        "ipv6": "2001:db8:f::",
+        "v6mask": 128
+    },
+    "routers": {
+        "r1": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo4_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo4_ibgp.json
new file mode 100644 (file)
index 0000000..bb72578
--- /dev/null
@@ -0,0 +1,428 @@
+{
+    "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-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "vm4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r1-link0": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r1-link1": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r1-link2": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r1-link3": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r1-link0": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r1-link1": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r1-link2": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r1-link3": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "vm1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "vm2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "vm3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "vm6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "200",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r1": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link1": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link2": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link3": {
+                                            "password": "r1"
+                                        }
+                                    }
+                                },
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link1": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link2": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link3": {
+                                            "password": "r1"
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r1": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link1": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link2": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link3": {
+                                            "password": "r1"
+                                        }
+                                    }
+                                },
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link1": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link2": {
+                                            "password": "r1"
+                                        },
+                                        "r2-link3": {
+                                            "password": "r1"
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "vm5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "300",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link0": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r3-link1": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r3-link2": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r3-link3": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link0": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r3-link1": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r3-link2": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        },
+                                        "r3-link3": {
+                                            "password": "r1",
+                                            "holddowntimer": 3,
+                                            "keepalivetimer": 1
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "vm1": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "vm2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "vm3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "vm4": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "vm5": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "vm6": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py
new file mode 100644 (file)
index 0000000..130f4fd
--- /dev/null
@@ -0,0 +1,1083 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+"""
+
+    -Verify static route ECMP functionality with 2 next hop
+
+    -Verify static route functionality with 2 next hop and different AD
+    value
+
+    -Verify RIB status when same route advertise via BGP and static route
+
+"""
+import sys
+import json
+import time
+import os
+import pytest
+import platform
+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 mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+    start_topology,
+    write_test_header,
+    write_test_footer,
+    reset_config_on_routers,
+    verify_rib,
+    create_static_routes,
+    check_address_types,
+    step,
+    create_interfaces_cfg,
+    shutdown_bringup_interface,
+    stop_router,
+    start_router,
+)
+from lib.topolog import logger
+from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo1_ibgp.json".format(CWD)
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {"ipv4": ["11.0.20.1/32", "11.0.20.2/32"], "ipv6": ["2::1/128", "2::2/128"]}
+NETWORK2 = {"ipv4": "11.0.20.1/32", "ipv6": "2::1/128"}
+
+PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"}
+
+
+class CreateTopo(Topo):
+    """
+    Test CreateTopo - topology 1.
+
+    * `Topo`: Topology object
+    """
+
+    def build(self, *_args, **_opts):
+        """Build function."""
+        tgen = get_topogen(self)
+
+        # Building topology from json file
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    """
+
+    Set up the pytest environment.
+
+    * `mod`: module name
+    """
+    global topo
+    testsuite_run_time = time.asctime(time.localtime(time.time()))
+    logger.info("Testsuite start time: {}".format(testsuite_run_time))
+    logger.info("=" * 40)
+
+    logger.info("Running setup_module to create topology")
+
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(CreateTopo, mod.__name__)
+    # ... and here it calls Mininet initialization functions.
+
+    # Starting topology, create tmp files which are loaded to routers
+    #  to start deamons and then start routers
+    start_topology(tgen)
+
+    # Creating configuration from JSON
+    build_config_from_json(tgen, topo)
+
+    if version_cmp(platform.release(), '4.19') < 0:
+        error_msg = ('These tests will not run. (have kernel "{}", '
+            'requires kernel >= 4.19)'.format(platform.release()))
+        pytest.skip(error_msg)
+
+    # Checking BGP convergence
+    global BGP_CONVERGENCE
+    global ADDR_TYPES
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    # Api call verify whether BGP is converged
+    BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+    assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+        BGP_CONVERGENCE
+    )
+
+    logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+    """
+    Teardown the pytest environment
+
+    * `mod`: module name
+    """
+
+    logger.info("Running teardown_module to delete topology")
+
+    tgen = get_topogen()
+
+    # Stop toplogy and Remove tmp files
+    tgen.stop_topology()
+
+    logger.info(
+        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+    )
+    logger.info("=" * 40)
+
+
+def populate_nh():
+    NEXT_HOP_IP = {
+        "nh1": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0],
+        },
+        "nh2": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0],
+        },
+    }
+    return NEXT_HOP_IP
+
+
+#####################################################
+#
+#   Tests starting
+#
+#####################################################
+
+
+def test_static_route_2nh_p0_tc_1_ibgp(request):
+    """
+    Verify static route ECMP functionality with 2 next hop
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+
+    step(
+        "Configure IPv4 static route (10.1.1.1) in R2 with next hop N1"
+        "(28.1.1.2 ) and N2 (29.1.1.2) , Static route next-hop present on"
+        "R1"
+    )
+    step("ex :- ip route 10.1.1.1/24 28.1.1.2 & ip route 10.1.1.1/24 29.1.1.1")
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                    },
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                    },
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "On R2, static route installed in RIB using show ip route"
+            " with 2 ECMP next hop "
+        )
+        nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("Configure IBGP IPv4 peering between R2 and R3 router.")
+        step("Configure redistribute static in BGP on R2 router")
+
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Remove the static route configured with nexthop N1 from running config")
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "delete": True,
+                    }
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "On R2, after removing the static route with N1 , "
+            "route become active with nexthop N2 and vice versa."
+        )
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB".format(tc_name)
+
+        nh = [NEXT_HOP_IP["nh2"][addr_type]]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("Configure the static route with nexthop N1")
+
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Remove the static route configured with nexthop N2 from running config")
+
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "delete": True,
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "On R2, after removing the static route with N2 , "
+            "route become active with nexthop N1 and vice versa."
+        )
+        nh = NEXT_HOP_IP["nh2"][addr_type]
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB".format(tc_name)
+
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("Configure the static route with nexthop N2")
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Shut nexthop interface N1")
+        intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"]
+
+        shutdown_bringup_interface(tgen, dut, intf, False)
+
+        step("Only one the nexthops should be active in RIB.")
+
+        nh = NEXT_HOP_IP["nh2"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB".format(tc_name)
+
+        dut = "r3"
+        result = verify_bgp_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            protocol=protocol,
+            next_hop=nh,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+        dut = "r2"
+        nh = [NEXT_HOP_IP["nh2"][addr_type]]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        dut = "r3"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Route is"
+        " missing in RIB".format(tc_name)
+
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+        dut = "r2"
+        step("No shut the nexthop interface N1")
+        shutdown_bringup_interface(tgen, dut, intf, True)
+
+        step(
+            "after shut of nexthop N1 , route become active "
+            "with nexthop N2 and vice versa."
+        )
+        nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][addr_type]]
+
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("Shut nexthop interface N2")
+        intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]
+        dut = "r2"
+        shutdown_bringup_interface(tgen, dut, intf, False)
+
+        step(
+            " after shut of nexthop N1 , route become active with "
+            "nexthop N2 and vice versa."
+        )
+        nh = NEXT_HOP_IP["nh2"][addr_type]
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB".format(tc_name)
+
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        dut = "r3"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Route is"
+        " missing in RIB".format(tc_name)
+
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+        step("No shut nexthop interface N2")
+        dut = "r2"
+        shutdown_bringup_interface(tgen, dut, intf, True)
+
+        step(
+            "after shut of nexthop N1 , route become active "
+            "with nexthop N2 and vice versa."
+        )
+        nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][addr_type]]
+
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        dut = "r3"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Route is"
+        " missing in RIB".format(tc_name)
+
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+        step("Reload the FRR router")
+        # stop/start -> restart FRR router and verify
+        stop_router(tgen, "r2")
+
+        start_router(tgen, "r2")
+
+        dut = "r2"
+        step(
+            "After reload of FRR router , static route installed"
+            " in RIB and FIB properly ."
+        )
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        dut = "r3"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route is"
+        " still present in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_static_route_2nh_admin_dist_p0_tc_2_ibgp(request):
+    """
+    Verify static route functionality with 2 next hop & different AD value
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+    step(
+        "Configure IPv4 static route (10.1.1.1) in R2 with next hop N1"
+        "(28.1.1.2 ) AD 10 and N2 (29.1.1.2) AD 20 , Static route next-hop"
+        "present on R1 \n ex :- ip route 10.1.1.1/24 28.1.1.2 10 & "
+        "ip route 10.1.1.1/24 29.1.1.2 20"
+    )
+
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    },
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "admin_distance": 20,
+                    },
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "On R2, static route installed in RIB using "
+            "show ip route with 2 next hop , lowest AD nexthop is active "
+        )
+        rte1_nh1 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        "missing in RIB".format(tc_name)
+
+        rte2_nh2 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "admin_distance": 20,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh2"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte2_nh2,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        "not active in RIB".format(tc_name)
+
+        step("Configure IBGP IPv4 peering between R2 and R3 router.")
+        step("Explicit route is added in R3 for R2 nexthop rechability")
+        rt3_rtes = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NEXT_HOP_IP["nh1"][addr_type] + "/32",
+                        "next_hop": topo["routers"]["r2"]["links"]["r3"][addr_type],
+                    },
+                    {
+                        "network": NEXT_HOP_IP["nh2"][addr_type] + "/32",
+                        "next_hop": topo["routers"]["r2"]["links"]["r3"][addr_type],
+                    },
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, rt3_rtes)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+        step("Configure redistribute static in BGP on R2 router")
+
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Remove the static route configured with nexthop N1 from running config")
+        rt1_nh1 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                        "delete": True,
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, rt1_nh1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "On R2, after removing the static route with N1 , "
+            "route become active with nexthop N2 and vice versa."
+        )
+        rte1_nh1 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte1_nh1,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        "missing in RIB".format(tc_name)
+
+        rte2_nh2 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "admin_distance": 20,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh2"][addr_type]]
+        result = verify_rib(
+            tgen, addr_type, dut, rte2_nh2, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        "not active in RIB".format(tc_name)
+
+        step("Configure the static route with nexthop N1")
+        rte1_nh1 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, rte1_nh1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Remove the static route configured with nexthop N2 from running config")
+        rte2_nh2 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "admin_distance": 20,
+                        "delete": True,
+                    }
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, rte2_nh2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "On R2, after removing the static route with N2 , "
+            "route become active with nexthop N1 and vice versa."
+        )
+        nh = NEXT_HOP_IP["nh2"][addr_type]
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte2_nh2,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB".format(tc_name)
+
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        result = verify_rib(
+            tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("Configure the static route with nexthop N2")
+        rte2_nh2 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "admin_distance": 20,
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, rte2_nh2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Shut nexthop interface N1")
+        intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"]
+
+        shutdown_bringup_interface(tgen, dut, intf, False)
+
+        step("after shut of nexthop N1 , route become active with nexthop N2")
+
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte1_nh1,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB".format(tc_name)
+
+        nh = [NEXT_HOP_IP["nh2"][addr_type]]
+        result = verify_rib(
+            tgen, addr_type, dut, rte2_nh2, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("No shut the nexthop interface N1")
+        shutdown_bringup_interface(tgen, dut, intf, True)
+
+        step(
+            "after shut of nexthop N1 , route become active "
+            "with nexthop N2 and vice versa."
+        )
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+
+        result = verify_rib(
+            tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("Shut nexthop interface N2")
+        intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]
+
+        shutdown_bringup_interface(tgen, dut, intf, False)
+
+        step(
+            " after shut of nexthop N1 , route become active with "
+            "nexthop N2 and vice versa."
+        )
+        nh = NEXT_HOP_IP["nh2"][addr_type]
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte2_nh2,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB".format(tc_name)
+
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        result = verify_rib(
+            tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        step("No shut nexthop interface N2")
+        shutdown_bringup_interface(tgen, dut, intf, True)
+
+        step(
+            "after shut of nexthop N1 , route become active "
+            "with nexthop N2 and vice versa."
+        )
+        rte1_nh1 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        "missing in RIB".format(tc_name)
+
+        rte2_nh2 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "admin_distance": 20,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh2"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte2_nh2,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        "not active in RIB".format(tc_name)
+
+        dut = "r3"
+        protocol = "bgp"
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte2_nh2,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        "not active in RIB".format(tc_name)
+
+        dut = "r2"
+        step("Reload the FRR router")
+        # stop/start -> restart FRR router and verify
+        stop_router(tgen, "r2")
+
+        start_router(tgen, "r2")
+
+        step(
+            "After reload of FRR router , static route installed"
+            " in RIB and FIB properly ."
+        )
+        rte1_nh1 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh1"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        "missing in RIB".format(tc_name)
+
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_bgp_rib(tgen, addr_type, dut, rte1_nh1, next_hop=nh)
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        "missing in RIB".format(tc_name)
+
+        rte2_nh2 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "admin_distance": 20,
+                    }
+                ]
+            }
+        }
+        nh = [NEXT_HOP_IP["nh2"][addr_type]]
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte2_nh2,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        "not active in RIB".format(tc_name)
+
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_bgp_rib(tgen, addr_type, dut, rte2_nh2, next_hop=nh)
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        "not active in RIB".format(tc_name)
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            rte2_nh2,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        "not active in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py
new file mode 100644 (file)
index 0000000..0a757c9
--- /dev/null
@@ -0,0 +1,1974 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+
+"""
+    -Verify static route functionality with 8 next hop different AD value
+    and BGP ECMP
+
+    -Verify 8 static route functionality with 8 next hop different AD
+
+    -Verify static route with 8 next hop with different AD value and 8
+    EBGP neighbors
+
+    -Verify static route with 8 next hop with different AD value and 8
+    IBGP neighbors
+
+    -Delete the static route and verify the RIB and FIB state
+
+    -Verify 8 static route functionality with 8 ECMP next hop
+"""
+import sys
+import json
+import time
+import os
+import pytest
+import platform
+from time import sleep
+import random
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+    start_topology,
+    write_test_header,
+    write_test_footer,
+    reset_config_on_routers,
+    verify_rib,
+    create_static_routes,
+    check_address_types,
+    step,
+    create_interfaces_cfg,
+    shutdown_bringup_interface,
+    stop_router,
+    start_router,
+)
+from lib.topolog import logger
+from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib
+from lib.topojson import build_topo_from_json, build_config_from_json
+from lib.topotest import version_cmp
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo2_ibgp.json".format(CWD)
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {
+    "ipv4": [
+        "11.0.20.1/32",
+        "11.0.20.2/32",
+        "11.0.20.3/32",
+        "11.0.20.4/32",
+        "11.0.20.5/32",
+        "11.0.20.6/32",
+        "11.0.20.7/32",
+        "11.0.20.8/32",
+    ],
+    "ipv6": [
+        "2::1/128",
+        "2::2/128",
+        "2::3/128",
+        "2::4/128",
+        "2::5/128",
+        "2::6/128",
+        "2::7/128",
+        "2::8/128",
+    ],
+}
+PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"}
+PREFIX2 = {"ipv4": "110.0.20.2/32", "ipv6": "20::2/128"}
+NEXT_HOP_IP = []
+topo_diag = """
+          Please view in a fixed-width font such as Courier.
+    +------+              +------+              +------+
+    |      +--------------+      +--------------+      |
+    |      |              |      |              |      |
+    |  R1  +---8 links----+ R2   +---8 links----+ R3   |
+    |      |              |      |              |      |
+    |      +--------------+      +--------------+      |
+    +------+              +------+              +------+
+
+"""
+
+
+class CreateTopo(Topo):
+    """
+    Test CreateTopo - topology 1.
+
+    * `Topo`: Topology object
+    """
+
+    def build(self, *_args, **_opts):
+        """Build function."""
+        tgen = get_topogen(self)
+
+        # Building topology from json file
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    """
+
+    Set up the pytest environment.
+
+    * `mod`: module name
+    """
+    global topo
+    testsuite_run_time = time.asctime(time.localtime(time.time()))
+    logger.info("Testsuite start time: {}".format(testsuite_run_time))
+    logger.info("=" * 40)
+
+    logger.info("Running setup_module to create topology")
+
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(CreateTopo, mod.__name__)
+    # ... and here it calls Mininet initialization functions.
+
+    # Starting topology, create tmp files which are loaded to routers
+    #  to start deamons and then start routers
+    start_topology(tgen)
+
+    # Creating configuration from JSON
+    build_config_from_json(tgen, topo)
+
+    if version_cmp(platform.release(), '4.19') < 0:
+        error_msg = ('These tests will not run. (have kernel "{}", '
+            'requires kernel >= 4.19)'.format(platform.release()))
+        pytest.skip(error_msg)
+
+    # Checking BGP convergence
+    global BGP_CONVERGENCE
+    global ADDR_TYPES
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # Api call verify whether BGP is converged
+    BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+    assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+        BGP_CONVERGENCE
+    )
+
+    logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+    """
+    Teardown the pytest environment
+
+    * `mod`: module name
+    """
+
+    logger.info("Running teardown_module to delete topology")
+
+    tgen = get_topogen()
+
+    # Stop toplogy and Remove tmp files
+    tgen.stop_topology()
+
+    logger.info(
+        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+    )
+    logger.info("=" * 40)
+
+
+def populate_nh():
+    NEXT_HOP_IP = {
+        "nh1": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0],
+        },
+        "nh2": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0],
+        },
+        "nh3": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0],
+        },
+        "nh4": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link3"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link3"]["ipv6"].split("/")[0],
+        },
+        "nh5": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link4"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link4"]["ipv6"].split("/")[0],
+        },
+        "nh6": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link5"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link5"]["ipv6"].split("/")[0],
+        },
+        "nh7": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link6"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link6"]["ipv6"].split("/")[0],
+        },
+        "nh8": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link7"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link7"]["ipv6"].split("/")[0],
+        },
+    }
+    return NEXT_HOP_IP
+
+
+#####################################################
+#
+#   Tests starting
+#
+#####################################################
+
+
+def test_static_rte_with_8ecmp_nh_p1_tc9_ibgp(request):
+    """
+    Verify 8 static route functionality with 8 ECMP next hop
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    NEXT_HOP_IP = populate_nh()
+    step("Configure 8 interfaces / links between R1 and R2")
+    step("Configure 8 interfaces / links between R2 and R3")
+    step("Configure 8 IBGP IPv4 peering between R2 and R3 router.")
+    reset_config_on_routers(tgen)
+
+    step(
+        "Configure 8 IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2) , N2(22.1.1.2) , N3(23.1.1.2) , N4(24.1.1.2) ,"
+        "N5(25.1.1.2) , N6(26.1.1.2) , N7(27.1.1.2) , N8(28.1.1.2) ,"
+        "Static route next-hop present on R1"
+    )
+    nh_all = {}
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+        nh_all[addr_type] = [
+            NEXT_HOP_IP["nh1"][addr_type],
+            NEXT_HOP_IP["nh2"][addr_type],
+            NEXT_HOP_IP["nh3"][addr_type],
+            NEXT_HOP_IP["nh4"][addr_type],
+            NEXT_HOP_IP["nh5"][addr_type],
+            NEXT_HOP_IP["nh6"][addr_type],
+            NEXT_HOP_IP["nh7"][addr_type],
+            NEXT_HOP_IP["nh8"][addr_type],
+        ]
+
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh_all[addr_type],
+            protocol=protocol,
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+    step("Configure redistribute static in BGP on R2 router")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+    step(
+        "Remove the static route configured with nexthop N1 to N8, one"
+        "by one from running config"
+    )
+    dut = "r2"
+    protocol = "static"
+    step(
+        "After removing the static route with N1 to N8 one by one , "
+        "verify that entry is removed from RIB and FIB of R3 "
+    )
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+
+            step(
+                "After removing the static route with N1 to N8 one by one , "
+                "verify that entry is removed from RIB and FIB of R3 "
+            )
+            nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type]
+            result = verify_rib(
+                tgen,
+                addr_type,
+                dut,
+                input_dict_4,
+                next_hop=nh,
+                protocol=protocol,
+                expected=False,
+            )
+            assert result is not True, "Testcase {} : Failed\nError: Routes is"
+            " still present in RIB".format(tc_name)
+
+    step("Configure the static route with nexthop N1 to N8, one by one")
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+
+            nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type]
+            result = verify_rib(
+                tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+            )
+            assert result is True, "Testcase {} : Failed\nError: Routes are"
+            " missing in RIB".format(tc_name)
+
+    protocol = "static"
+    step("Random shut of the nexthop interfaces")
+    randnum = random.randint(0, 7)
+    # Shutdown interface
+    dut = "r2"
+    step(
+        " interface which is about to be shut no shut between r1 and r2 is " "%s",
+        topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"],
+    )
+    intf = topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"]
+    shutdown_bringup_interface(tgen, dut, intf, False)
+
+    step("Random no shut of the nexthop interfaces")
+    # Bringup interface
+    shutdown_bringup_interface(tgen, dut, intf, True)
+
+    step(
+        "After random shut/no shut of nexthop , only that "
+        "nexthop deleted/added from all the routes , other nexthop remain "
+        "unchanged"
+    )
+    dut = "r2"
+    protocol = "static"
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                    }
+                ]
+            }
+        }
+    result = verify_rib(
+        tgen,
+        addr_type,
+        dut,
+        input_dict_4,
+        next_hop=nh_all[addr_type],
+        protocol=protocol,
+    )
+    assert result is True, "Testcase {} : Failed \nError: Routes are"
+    " missing in RIB".format(tc_name)
+
+    step("Remove random static route with all the nexthop")
+    dut = "r2"
+    randnum = random.randint(1, 7)
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum)][addr_type],
+                        "delete": True,
+                    }
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "After delete of random route , that route only got deleted from"
+            " RIB/FIB other route are showing properly"
+        )
+        nh = NEXT_HOP_IP["nh{}".format(randnum)][addr_type]
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum)][addr_type],
+                    }
+                ]
+            }
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step("Reload the FRR router")
+    # stop/start -> restart FRR router and verify
+    stop_router(tgen, "r2")
+    start_router(tgen, "r2")
+
+    step(
+        "After reload of FRR router , static route "
+        "installed in RIB and FIB properly ."
+    )
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        nhp = 1
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                    }
+                ]
+            }
+        }
+        logger.info("Verifying %s routes on r2", addr_type)
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh_all[addr_type],
+            protocol=protocol,
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+    step("Remove the redistribute static knob")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "redistribute": [
+                                    {"redist_type": "static", "delete": True}
+                                ]
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "After removing the BGP neighbor or redistribute static knob , "
+            "verify route got clear from RIB and FIB of R3 routes "
+        )
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " still present in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ibgp(request):
+    """
+    Verify static route functionality with 8 next hop different AD
+    value and BGP ECMP
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    step("Configure 8 interfaces / links between R1 and R2 ,")
+    step("Configure 8 interlaces/links between R2 and R3")
+    step(
+        "Configure IBGP IPv4 peering over loopback interface between"
+        "R2 and R3 router."
+    )
+    step("Configure redistribute static in BGP on R2 router")
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+    nh_all = {}
+    for addr_type in ADDR_TYPES:
+        nh_all[addr_type] = []
+        for nhp in range(1, 9):
+            nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+    step(
+        "Configure IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+        "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+        "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop"
+        "present on R1"
+    )
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+
+        step(
+            "On R2, static route installed in RIB using "
+            "show ip route with 8 next hop , lowest AD nexthop is active"
+        )
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+            wait=2,
+            attempts=3,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " are missing in RIB".format(tc_name)
+
+    step(
+        "Remove the static route configured with nexthop N1 to N8, one"
+        "by one from running config"
+    )
+
+    for addr_type in ADDR_TYPES:
+        # delete static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "After removing the static route with N1 to N8 one by one , "
+        "route become active with next preferred nexthop and nexthop which "
+        "got removed is not shown in RIB and FIB"
+    )
+    result = verify_rib(
+        tgen,
+        addr_type,
+        dut,
+        input_dict_4,
+        next_hop=nh_all[addr_type],
+        protocol=protocol,
+        expected=False,
+    )
+    assert result is not True, "Testcase {} : Failed \nError: Routes are"
+    " still present in RIB".format(tc_name)
+
+    step("Configure the static route with nexthop N1 to N8, one by one")
+
+    for addr_type in ADDR_TYPES:
+        # add static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        " After configuring them, route is always active with lowest AD"
+        " value and all the nexthop populated in RIB and FIB again"
+    )
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+            wait=2,
+            attempts=3,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " are missing in RIB".format(tc_name)
+
+    step("Random shut of the nexthop interfaces")
+    randnum = random.randint(0, 7)
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        input_dict_5 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+                    }
+                ]
+            }
+        }
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_5,
+            next_hop=nhip,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \n"
+        "Error: Routes are still present in RIB".format(tc_name)
+
+    step("Random no shut of the nexthop interfaces")
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \n"
+        "Error: Routes are missing in RIB".format(tc_name)
+
+    protocol = "bgp"
+    # this is next hop reachability route  in r3 as we are using ibgp
+    dut = "r3"
+    for addr_type in ADDR_TYPES:
+        nh_as_rte = NEXT_HOP_IP["nh1"][addr_type] + "/32"
+        # add static routes
+        nh_static_rte = {
+            "r3": {"static_routes": [{"network": nh_as_rte, "next_hop": "Null0"}]}
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, nh_static_rte)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "After each interface shut and no shut between R2 -R3 ,verify static"
+        "route is present in the RIB & FIB of R3 & R2 RIB/FIB is remain"
+        " unchanged"
+    )
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n"
+        "Error: Routes are missing in RIB".format(tc_name)
+
+    protocol = "static"
+    dut = "r2"
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert (
+            result is True
+        ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name)
+
+    protocol = "bgp"
+    dut = "r3"
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert (
+            result is True
+        ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name)
+
+    step("Reload the FRR router")
+    # stop/start -> restart FRR router and verify
+    stop_router(tgen, "r2")
+
+    start_router(tgen, "r2")
+
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert result is True, (
+            "Testcase {} : Failed \n"
+            "Error: Routes are still present in RIB".format(tc_name)
+        )
+
+    step("BGP neighbor remove and add")
+    for rtr in ["r2", "r3"]:
+        if "bgp" in topo["routers"][rtr].keys():
+            delete_bgp = {rtr: {"bgp": {"delete": True}}}
+            result = create_router_bgp(tgen, topo, delete_bgp)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+
+    create_router_bgp(tgen, topo["routers"])
+
+    NEXT_HOP_IP = populate_nh()
+    step("Verify routes are still present after delete and add bgp")
+    dut = "r2"
+    protocol = "static"
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert result is True, (
+            "Testcase {} : Failed \n"
+            "Error: Routes are still present in RIB".format(tc_name)
+        )
+
+    dut = "r3"
+    protocol = "bgp"
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert result is True, (
+            "Testcase {} : Failed \n"
+            "Error: Routes are still present in RIB".format(tc_name)
+        )
+
+    step("Remove the redistribute static knob")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "redistribute": [
+                                    {"redist_type": "static", "delete": True}
+                                ]
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        logger.info("Remove redistribute static")
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+        step("verify that routes are deleted from R3 routing table")
+
+        dut = "r3"
+        protocol = "bgp"
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " strill present in RIB of R3".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_static_route_8nh_diff_AD_ibgp_ecmp_p1_tc7_ibgp(request):
+    """
+    Verify static route with 8 next hop with different AD value and 8
+    IBGP neighbors
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    step("Configure 8 interfaces / links between R1 and R2")
+    step("Configure 8 interlaces/links between R2 and R3")
+    step("Configure 8 IBGP IPv4 peering between R2 and R3")
+
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+
+    step("Configure redistribute static in BGP on R2 router")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "Configure IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+        "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+        "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop"
+        "present on R1"
+    )
+    nh_all = {}
+    for addr_type in ADDR_TYPES:
+        nh_all[addr_type] = []
+        for nhp in range(1, 9):
+            nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+
+        step(
+            "On R2, static route installed in RIB using "
+            "show ip route with 8 next hop , lowest AD nexthop is active"
+        )
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " are missing in RIB".format(tc_name)
+
+    step(
+        "Remove the static route configured with nexthop N1 to N8, one"
+        "by one from running config"
+    )
+
+    for addr_type in ADDR_TYPES:
+        # delete static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "After removing the static route with N1 to N8 one by one , "
+        "route become active with next preferred nexthop and nexthop which "
+        "got removed is not shown in RIB and FIB"
+    )
+    result = verify_rib(
+        tgen,
+        addr_type,
+        dut,
+        input_dict_4,
+        next_hop=nh_all[addr_type],
+        protocol=protocol,
+        expected=False,
+    )
+    assert result is not True, "Testcase {} : Failed \nError: Routes are"
+    " still present in RIB".format(tc_name)
+
+    step("Configure the static route with nexthop N1 to N8, one by one")
+
+    for addr_type in ADDR_TYPES:
+        # add static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        " After configuring them, route is always active with lowest AD"
+        " value and all the nexthop populated in RIB and FIB again"
+    )
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " are missing in RIB".format(tc_name)
+
+    step("Random shut of the nexthop interfaces")
+    randnum = random.randint(0, 7)
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        input_dict_5 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+                    }
+                ]
+            }
+        }
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_5,
+            next_hop=nhip,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \n"
+        "Error: Routes are still present in RIB".format(tc_name)
+
+    step("Random no shut of the nexthop interfaces")
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \n"
+        "Error: Routes are missing in RIB".format(tc_name)
+
+    dut = "r2"
+    protocol = "bgp"
+
+    # this is next hop reachability route  in r3 as we are using ibgp
+    dut = "r3"
+    for addr_type in ADDR_TYPES:
+        nh_as_rte = NEXT_HOP_IP["nh1"][addr_type] + "/32"
+        # add static routes
+        nh_static_rte = {
+            "r3": {"static_routes": [{"network": nh_as_rte, "next_hop": "Null0"}]}
+        }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, nh_static_rte)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "After each interface shut and no shut between R2 -R3 ,verify static"
+        "route is present in the RIB & FIB of R3 & R2 RIB/FIB is remain"
+        " unchanged"
+    )
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n"
+        "Error: Routes are missing in RIB".format(tc_name)
+
+    protocol = "static"
+    dut = "r2"
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert (
+            result is True
+        ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name)
+
+    protocol = "bgp"
+    dut = "r3"
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert (
+            result is True
+        ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name)
+
+    step("Reload the FRR router")
+    # stop/start -> restart FRR router and verify
+    stop_router(tgen, "r2")
+
+    start_router(tgen, "r2")
+
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert result is True, (
+            "Testcase {} : Failed \n"
+            "Error: Routes are still present in RIB".format(tc_name)
+        )
+
+    step("BGP neighbor remove and add")
+    for rtr in ["r2", "r3"]:
+        if "bgp" in topo["routers"][rtr].keys():
+            delete_bgp = {rtr: {"bgp": {"delete": True}}}
+            result = create_router_bgp(tgen, topo, delete_bgp)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+
+    create_router_bgp(tgen, topo["routers"])
+
+    NEXT_HOP_IP = populate_nh()
+    step("Verify routes are still present after delete and add bgp")
+    dut = "r2"
+    protocol = "static"
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert result is True, (
+            "Testcase {} : Failed \n"
+            "Error: Routes are still present in RIB".format(tc_name)
+        )
+
+    dut = "r3"
+    protocol = "bgp"
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert result is True, (
+            "Testcase {} : Failed \n"
+            "Error: Routes are still present in RIB".format(tc_name)
+        )
+
+    step("Remove the redistribute static knob")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "redistribute": [
+                                    {"redist_type": "static", "delete": True}
+                                ]
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        logger.info("Remove redistribute static")
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+        step("verify that routes are deleted from R3 routing table")
+
+        dut = "r3"
+        protocol = "bgp"
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " still present in RIB of R3".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc10_ibgp(request):
+    """
+    Verify 8 static route functionality with 8 next hop different AD'
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    NEXT_HOP_IP = populate_nh()
+
+    step("Configure 8 interfaces / links between R1 and R2 ")
+    step("Configure 8 IBGP IPv4 peering between R2 and R3 router.")
+    reset_config_on_routers(tgen)
+
+    step(
+        "Configure IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+        "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+        "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80"
+    )
+    step(
+        "Configure nexthop AD in such way for static route S1 , N1 is"
+        "preferred and for S2 , N2 is preferred and so on .."
+    )
+    nh_all = {}
+    for addr_type in ADDR_TYPES:
+        nh_all[addr_type] = []
+        for nhp in range(1, 9):
+            nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+            second_rte = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX2[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, second_rte)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+
+        step(
+            "On R2, static route installed in RIB using "
+            "show ip route with 8 next hop , lowest AD nexthop is active"
+        )
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+        step("Verify that highest AD nexthop are inactive")
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+            wait=2,
+            attempts=3,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " are missing in RIB".format(tc_name)
+
+    step("Configure redistribute static in BGP on R2 router")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "Remove the static route configured with nexthop N1 to N8, one"
+        "by one from running config"
+    )
+
+    for addr_type in ADDR_TYPES:
+        # delete static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "After removing the static route with N1 to N8 one by one , "
+            "route become active with next preferred nexthop and nexthop which"
+            "got removed is not shown in RIB and FIB"
+        )
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " still present in RIB".format(tc_name)
+
+    step("Configure the static route with nexthop N1 to N8, one by one")
+    for addr_type in ADDR_TYPES:
+        # add static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        " After configuring them, route is always active with lowest AD"
+        " value and all the nexthop populated in RIB and FIB again"
+    )
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}}
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        "lowest AD  is missing in RIB".format(tc_name)
+
+    step("Random shut of the nexthop interfaces")
+    randnum = random.randint(0, 7)
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        input_dict_5 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+                    }
+                ]
+            }
+        }
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_5,
+            next_hop=nhip,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \n"
+        "Error: Routes are still present in RIB".format(tc_name)
+
+    step("Random no shut of the nexthop interfaces")
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \n"
+        "Error: Routes are missing in RIB".format(tc_name)
+
+    step("Remove random static route with all the nexthop")
+    for addr_type in ADDR_TYPES:
+        # delete static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+
+            step(
+                "After removing the static route with N1 to N8 one by one , "
+                "route become active with next preferred nexthop and nexthop "
+                "which got removed is not shown in RIB and FIB"
+            )
+            nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type]
+            result = verify_rib(
+                tgen,
+                addr_type,
+                dut,
+                input_dict_4,
+                next_hop=nh,
+                protocol=protocol,
+                expected=False,
+            )
+            assert result is not True, "Testcase {} : Failed \nError: Route "
+            " is still present in RIB".format(tc_name)
+
+        step("Reconfigure the deleted routes and verify they are installed")
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+
+            dut = "r2"
+            protocol = "static"
+            nh = NEXT_HOP_IP["nh1"][addr_type]
+            result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+            assert result is True, "Testcase {} : Failed \nError: Route "
+            " is still present in RIB".format(tc_name)
+
+            step("Reload the FRR router")
+            # stop/start -> restart FRR router and verify
+            stop_router(tgen, "r2")
+
+            start_router(tgen, "r2")
+
+            step("After reloading, verify that routes are still present in R2.")
+            result = verify_rib(
+                tgen,
+                addr_type,
+                dut,
+                second_rte,
+                next_hop=nh,
+                protocol=protocol,
+                fib=True,
+            )
+            assert result is True, (
+                "Testcase {} : Failed \nError: Route "
+                " is missing in RIB".format(tc_name)
+            )
+
+    step("Remove the redistribute static knob")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "redistribute": [
+                                    {"redist_type": "static", "delete": True}
+                                ]
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "After removing the BGP neighbor or redistribute static knob , "
+        "verify route got clear from RIB and FIB of R3 routes "
+    )
+    dut = "r3"
+    protocol = "bgp"
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                    }
+                ]
+            }
+        }
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " still present in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_static_route_delete_p0_tc11_ibgp(request):
+    """
+    Delete the static route and verify the RIB and FIB state
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    NEXT_HOP_IP = populate_nh()
+
+    step("Configure 8 interfaces / links between R1 and R2 ")
+    step("Configure 8 IBGP IPv4 peering between R2 and R3 router.")
+    reset_config_on_routers(tgen)
+
+    step(
+        "Configure IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+        "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+        "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80"
+    )
+    step(
+        "Configure nexthop AD in such way for static route S1 , N1 is"
+        "preferred and for S2 , N2 is preferred and so on .."
+    )
+    nh_all = {}
+    for addr_type in ADDR_TYPES:
+        nh_all[addr_type] = []
+        for nhp in range(1, 9):
+            nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+            second_rte = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX2[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, second_rte)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+
+        step(
+            "On R2, static route installed in RIB using "
+            "show ip route with 8 next hop , lowest AD nexthop is active"
+        )
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+        step("Verify that highest AD nexthop are inactive")
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " are missing in RIB".format(tc_name)
+
+    step("Configure redistribute static in BGP on R2 router")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step("Remove the redistribute static knob")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "redistribute": [
+                                    {"redist_type": "static", "delete": True}
+                                ]
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "Verify after removing the redistribute static from BGP all the"
+            "routes got delete from RIB and FIB of R3 "
+        )
+
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " still present in RIB".format(tc_name)
+
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+            second_rte = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX2[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, second_rte)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+
+        step(
+            " After removing all the routes and nexthop from R2 , "
+            " verify R2 RIB and FIB is cleared"
+        )
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " still active in RIB".format(tc_name)
+    write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py
new file mode 100644 (file)
index 0000000..924fb3a
--- /dev/null
@@ -0,0 +1,875 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+"""
+    -Verify static route ECMP functionality with 8 next hop
+
+    -Verify static route functionality with 8 next hop different AD value
+
+    -Verify static route with tag option
+
+    -Verify BGP did not install the static route when it receive route
+    with local next hop
+
+"""
+import sys
+import json
+import time
+import os
+import pytest
+import platform
+from copy import deepcopy
+import random
+from re import search as re_search
+
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+from lib.common_config import (
+    start_topology,
+    write_test_header,
+    write_test_footer,
+    reset_config_on_routers,
+    verify_rib,
+    create_static_routes,
+    check_address_types,
+    step,
+    create_interfaces_cfg,
+    shutdown_bringup_interface,
+    stop_router,
+    start_router,
+)
+from lib.topolog import logger
+from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo3_ibgp.json".format(CWD)
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {
+    "ipv4": [
+        "11.0.20.1/32",
+        "11.0.20.2/32",
+        "11.0.20.3/32",
+        "11.0.20.4/32",
+        "11.0.20.5/32",
+        "11.0.20.6/32",
+        "11.0.20.7/32",
+        "11.0.20.8/32",
+    ],
+    "ipv6": [
+        "2::1/128",
+        "2::2/128",
+        "2::3/128",
+        "2::4/128",
+        "2::5/128",
+        "2::6/128",
+        "2::7/128",
+        "2::8/128",
+    ],
+}
+PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"}
+NETWORK2 = {"ipv4": ["11.0.20.1/32"], "ipv6": ["2::1/128"]}
+NEXT_HOP_IP = []
+
+
+class CreateTopo(Topo):
+    """
+    Test CreateTopo - topology 1.
+
+    * `Topo`: Topology object
+    """
+
+    def build(self, *_args, **_opts):
+        """Build function."""
+        tgen = get_topogen(self)
+
+        # Building topology from json file
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    """
+
+    Set up the pytest environment.
+
+    * `mod`: module name
+    """
+    global topo
+    testsuite_run_time = time.asctime(time.localtime(time.time()))
+    logger.info("Testsuite start time: {}".format(testsuite_run_time))
+    logger.info("=" * 40)
+
+    logger.info("Running setup_module to create topology")
+
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(CreateTopo, mod.__name__)
+    # ... and here it calls Mininet initialization functions.
+
+    # Starting topology, create tmp files which are loaded to routers
+    #  to start deamons and then start routers
+    start_topology(tgen)
+
+    # Creating configuration from JSON
+    build_config_from_json(tgen, topo)
+
+    if version_cmp(platform.release(), '4.19') < 0:
+        error_msg = ('These tests will not run. (have kernel "{}", '
+            'requires kernel >= 4.19)'.format(platform.release()))
+        pytest.skip(error_msg)
+
+    # Checking BGP convergence
+    global BGP_CONVERGENCE
+    global ADDR_TYPES
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    # Api call verify whether BGP is converged
+    BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+    assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+        BGP_CONVERGENCE
+    )
+
+    logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+    """
+    Teardown the pytest environment
+
+    * `mod`: module name
+    """
+
+    logger.info("Running teardown_module to delete topology")
+
+    tgen = get_topogen()
+
+    # Stop toplogy and Remove tmp files
+    tgen.stop_topology()
+
+    logger.info(
+        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+    )
+    logger.info("=" * 40)
+
+
+def populate_nh():
+    NEXT_HOP_IP = {
+        "nh1": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0],
+        },
+        "nh2": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0],
+        },
+        "nh3": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0],
+        },
+        "nh4": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link3"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link3"]["ipv6"].split("/")[0],
+        },
+        "nh5": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link4"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link4"]["ipv6"].split("/")[0],
+        },
+        "nh6": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link5"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link5"]["ipv6"].split("/")[0],
+        },
+        "nh7": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link6"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link6"]["ipv6"].split("/")[0],
+        },
+        "nh8": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link7"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link7"]["ipv6"].split("/")[0],
+        },
+    }
+    return NEXT_HOP_IP
+
+
+#####################################################
+#
+#   Tests starting
+#
+#####################################################
+
+
+def test_staticroute_with_ecmp_p0_tc3_ibgp(request):
+    """
+    Verify static route ECMP functionality with 8 next hop'
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+
+    step("Configure 8 interfaces / links between R1 and R2,")
+    step(
+        "Configure IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2), N2(22.1.1.2), N3(23.1.1.2), N4(24.1.1.2),"
+        "N5(25.1.1.2), N6(26.1.1.2), N7(27.1.1.2),N8(28.1.1.2), Static"
+        "route next-hop present on R1"
+    )
+
+    step("Configure IBGP IPv4 peering between R2 and R3 router.")
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+        nh = [
+            NEXT_HOP_IP["nh1"][addr_type],
+            NEXT_HOP_IP["nh2"][addr_type],
+            NEXT_HOP_IP["nh3"][addr_type],
+            NEXT_HOP_IP["nh4"][addr_type],
+            NEXT_HOP_IP["nh5"][addr_type],
+            NEXT_HOP_IP["nh6"][addr_type],
+            NEXT_HOP_IP["nh7"][addr_type],
+            NEXT_HOP_IP["nh8"][addr_type],
+        ]
+
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+    step("Configure redistribute static in BGP on R2 router")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "Remove the static route configured with nexthop N1 to N8, one"
+        "by one from running config"
+    )
+    for addr_type in ADDR_TYPES:
+        # delete static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " still present in RIB".format(tc_name)
+
+    step("Configure the static route with nexthop N1 to N8, one by" "one")
+
+    for addr_type in ADDR_TYPES:
+        # add static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    result = verify_rib(
+        tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+    )
+    assert result is True, "Testcase {} : Failed \nError: Routes are"
+    " missing in RIB".format(tc_name)
+
+    step("Random shut of the nexthop interfaces")
+    randnum = random.randint(0, 7)
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        input_dict_5 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+                    }
+                ]
+            }
+        }
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_5,
+            next_hop=nhip,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \n"
+        "Error: Routes are still present in RIB".format(tc_name)
+
+    step("Random no shut of the nexthop interfaces")
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \n"
+        "Error: Routes are missing in RIB".format(tc_name)
+
+    step("Reload the FRR router")
+    # stop/start -> restart FRR router and verify
+    stop_router(tgen, "r2")
+    start_router(tgen, "r2")
+
+    result = verify_rib(
+        tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+    )
+    assert result is True, "Testcase {} : Failed \nError: Routes are"
+    " missing in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_staticroute_with_ecmp_with_diff_AD_p0_tc4_ibgp(request):
+    """
+    Verify static route ECMP functionality with 8 next hop
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+
+    step("Configure 8 interfaces / links between R1 and R2,")
+    step("Configure IBGP IPv4 peering between R2 and R3 router.")
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+    nh_all = {}
+    for addr_type in ADDR_TYPES:
+        nh_all[addr_type] = []
+        for nhp in range(1, 9):
+            nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+    step(
+        "Configure IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+        "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+        "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop"
+        "present on R1"
+    )
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+
+        step(
+            "On R2, static route installed in RIB using "
+            "show ip route with 8 next hop, lowest AD nexthop is active"
+        )
+        step("On R2, static route with lowest AD nexthop installed in FIB")
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        " lowest AD is missing in RIB".format(tc_name)
+
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " with high AD are active in RIB".format(tc_name)
+
+    step("Configure redistribute static in BGP on R2 router")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+
+        logger.info("Configuring redistribute static")
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "After configuring them, route is always active with lowest AD"
+            "value and all the nexthop populated in RIB and FIB again "
+        )
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        " lowest AD is missing in RIB".format(tc_name)
+
+    step(
+        "Remove the static route configured with nexthop N1 to N8, one"
+        "by one from running config"
+    )
+
+    for addr_type in ADDR_TYPES:
+        # delete static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "After removing the static route with N1 to N8 one by one, "
+        "route become active with next preferred nexthop and nexthop which "
+        "got removed is not shown in RIB and FIB"
+    )
+    result = verify_rib(
+        tgen,
+        addr_type,
+        dut,
+        input_dict_4,
+        next_hop=nh_all[addr_type],
+        protocol=protocol,
+        expected=False,
+    )
+    assert result is not True, "Testcase {} : Failed \nError: Routes are"
+    " still present in RIB".format(tc_name)
+
+    step("Configure the static route with nexthop N1 to N8, one by" "one")
+    for addr_type in ADDR_TYPES:
+        # add static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("On R2, static route with lowest AD nexthop installed in FIB")
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        " lowest AD is missing in RIB".format(tc_name)
+
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " with high AD are active in RIB".format(tc_name)
+
+    step("Random shut of the nexthop interfaces")
+    randnum = random.randint(0, 7)
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        input_dict_5 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+                    }
+                ]
+            }
+        }
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_5,
+            next_hop=nhip,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \n"
+        "Error: Routes are still present in RIB".format(tc_name)
+
+    step("Random no shut of the nexthop interfaces")
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \n"
+        "Error: Routes are missing in RIB".format(tc_name)
+
+    step("Reload the FRR router")
+    # stop/start -> restart FRR router and verify
+    stop_router(tgen, "r2")
+    start_router(tgen, "r2")
+
+    step(
+        "After reload of FRR router, static route installed "
+        "in RIB and FIB properly ."
+    )
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        " lowest AD is missing in RIB".format(tc_name)
+
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " with high AD are active in RIB".format(tc_name)
+
+    step("Remove the redistribute static knob")
+
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "redistribute": [
+                                    {"redist_type": "static", "delete": True}
+                                ]
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        logger.info("Remove redistribute static")
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+        step("verify that routes are deleted from R3 routing table")
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " strill present in RIB of R3".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_bgp_local_nexthop_p1_tc14_ibgp(request):
+    """
+    Verify BGP did not install the static route when it receive route
+    with local next hop
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    step("Configure BGP IPv4 session between R2 and R3")
+    step("Configure IPv4 static route on R2")
+    reset_config_on_routers(tgen)
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": topo["routers"]["r3"]["links"]["r2-link0"][
+                            addr_type
+                        ].split("/")[0],
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Configure redistribute static in the BGP")
+
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Verify R2 BGP table has IPv4 route")
+        dut = "r2"
+        result = verify_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB of R2".format(tc_name)
+
+        step(" Verify route did not install in the R3 BGP table, RIB/FIB")
+        dut = "r3"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4, expected=False)
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in BGP RIB of R2".format(tc_name)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, expected=False)
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB of R2".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py
new file mode 100644 (file)
index 0000000..fdbfad2
--- /dev/null
@@ -0,0 +1,991 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+
+Following tests are covered in the script.
+
+- Verify static route are blocked from route-map and prefix-list
+    applied in BGP nbrs
+"""
+
+import sys
+import json
+import time
+import os
+import pytest
+import platform
+import ipaddress
+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 mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+from lib.common_config import (
+    start_topology,
+    write_test_header,
+    write_test_footer,
+    reset_config_on_routers,
+    verify_rib,
+    check_address_types,
+    step,
+    create_prefix_lists,
+    create_route_maps,
+    create_interfaces_cfg,
+    verify_prefix_lists,
+    verify_route_maps,
+)
+from lib.topolog import logger
+from lib.bgp import (
+    verify_bgp_convergence,
+    create_router_bgp,
+    clear_bgp_and_verify,
+    clear_bgp,
+)
+from lib.topojson import build_topo_from_json, build_config_from_json
+from lib.topotest import version_cmp
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo4_ibgp.json".format(CWD)
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {"ipv4": "2.2.2.2/32", "ipv6": "22:22::2/128"}
+NEXT_HOP_IP = {}
+
+
+class CreateTopo(Topo):
+    """
+    Test CreateTopo - topology 1.
+
+    * `Topo`: Topology object
+    """
+
+    def build(self, *_args, **_opts):
+        """Build function."""
+        tgen = get_topogen(self)
+
+        # Building topology from json file
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    """
+    Set up the pytest environment.
+    * `mod`: module name
+    """
+    global topo
+    testsuite_run_time = time.asctime(time.localtime(time.time()))
+    logger.info("Testsuite start time: {}".format(testsuite_run_time))
+    logger.info("=" * 40)
+
+    logger.info("Running setup_module to create topology")
+
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(CreateTopo, mod.__name__)
+    # ... and here it calls Mininet initialization functions.
+
+    # Starting topology, create tmp files which are loaded to routers
+    #  to start deamons and then start routers
+    start_topology(tgen)
+
+    # Creating configuration from JSON
+    build_config_from_json(tgen, topo)
+
+    if version_cmp(platform.release(), '4.19') < 0:
+        error_msg = ('These tests will not run. (have kernel "{}", '
+            'requires kernel >= 4.19)'.format(platform.release()))
+        pytest.skip(error_msg)
+
+    # Checking BGP convergence
+    global BGP_CONVERGENCE
+    global ADDR_TYPES
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    # Api call verify whether BGP is converged
+    BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+    assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+        BGP_CONVERGENCE
+    )
+
+    logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+    """
+    Teardown the pytest environment.
+
+    * `mod`: module name
+    """
+    logger.info("Running teardown_module to delete topology")
+
+    tgen = get_topogen()
+
+    # Stop toplogy and Remove tmp files
+    tgen.stop_topology()
+
+    logger.info(
+        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+    )
+    logger.info("=" * 40)
+
+
+#####################################################
+#
+#   Tests starting
+#
+#####################################################
+def test_static_routes_rmap_pfxlist_p0_tc7_ibgp(request):
+    """
+    Verify static route are blocked from route-map & prefix-list applied in BGP
+    nbrs
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    reset_config_on_routers(tgen)
+    step("Configure holddown timer = 1 keep alive = 3 in all the neighbors")
+    step("verify bgp convergence before starting test case")
+
+    bgp_convergence = verify_bgp_convergence(tgen, topo)
+    assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, bgp_convergence
+    )
+
+    step(
+        "Configure 4 IPv4 and 4 IPv6 nbrs with password with mismatch "
+        " authentication between FRR routers "
+    )
+
+    for addr_type in ADDR_TYPES:
+        # Api call to modfiy BGP timerse
+        input_dict = {
+            "r2": {
+                "bgp": {
+                    "local_as": "200",
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r1": {
+                                        "dest_link": {
+                                            "r2-link0": {"password": "r2"},
+                                            "r2-link1": {"password": "r2"},
+                                            "r2-link2": {"password": "r2"},
+                                            "r2-link3": {"password": "r2"},
+                                        }
+                                    },
+                                    "r3": {
+                                        "dest_link": {
+                                            "r2-link0": {"password": "r2"},
+                                            "r2-link1": {"password": "r2"},
+                                            "r2-link2": {"password": "r2"},
+                                            "r2-link3": {"password": "r2"},
+                                        }
+                                    },
+                                }
+                            }
+                        }
+                    },
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, deepcopy(input_dict))
+        assert result is True, "Testcase {} :Failed \n Error: {}".format(
+            tc_name, result
+        )
+        clear_bgp(tgen, addr_type, "r2")
+
+    step(" All BGP nbrs are down as authentication is mismatch on both" " the sides")
+
+    bgp_convergence = verify_bgp_convergence(tgen, topo, expected=False)
+    assert bgp_convergence is not True, "Testcase {} : "
+    "Failed \n BGP nbrs must be down. Error: {}".format(tc_name, bgp_convergence)
+
+    step(
+        "Configure 4 IPv4 and 4 IPv6 nbrs with macthing password  "
+        " authentication between FRR routers "
+    )
+    for addr_type in ADDR_TYPES:
+        input_dict = {
+            "r2": {
+                "bgp": {
+                    "local_as": "200",
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r1": {
+                                        "dest_link": {
+                                            "r2-link0": {"password": "r1"},
+                                            "r2-link1": {"password": "r1"},
+                                            "r2-link2": {"password": "r1"},
+                                            "r2-link3": {"password": "r1"},
+                                        }
+                                    },
+                                    "r3": {
+                                        "dest_link": {
+                                            "r2-link0": {"password": "r1"},
+                                            "r2-link1": {"password": "r1"},
+                                            "r2-link2": {"password": "r1"},
+                                            "r2-link3": {"password": "r1"},
+                                        }
+                                    },
+                                }
+                            }
+                        }
+                    },
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, deepcopy(input_dict))
+        assert result is True, "Testcase {} :Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step("All BGP nbrs are up as authentication is matched now")
+    bgp_convergence = verify_bgp_convergence(tgen, topo)
+    assert bgp_convergence is True, "Testcase {} : Failed \n " "Error: {}".format(
+        tc_name, bgp_convergence
+    )
+
+    step("Create prefix list P1 to permit VM3 & deny VM1 v4 & v6 routes")
+    step("Create prefix list P2 to permit VM6 IPv4 and IPv6 routes")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "prefix_lists": {
+                    addr_type: {
+                        "pf_list_1_{}".format(addr_type): [
+                            {
+                                "seqid": 10,
+                                "network": topo["routers"]["r2"]["links"]["vm3"][
+                                    addr_type
+                                ],
+                                "action": "permit",
+                            },
+                            {
+                                "seqid": 20,
+                                "network": topo["routers"]["r2"]["links"]["vm1"][
+                                    addr_type
+                                ],
+                                "action": "deny",
+                            },
+                        ],
+                        "pf_list_2_{}".format(addr_type): [
+                            {
+                                "seqid": 10,
+                                "network": topo["routers"]["r2"]["links"]["vm6"][
+                                    addr_type
+                                ],
+                                "action": "permit",
+                            }
+                        ],
+                    }
+                }
+            }
+        }
+        result = create_prefix_lists(tgen, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "Prefix list created with matching networks deny or permit "
+            "show ip prefix list"
+        )
+        result = verify_prefix_lists(tgen, input_dict_2)
+        assert result is not True, "Testcase {} : Failed \n"
+        " Error: {}".format(tc_name, result)
+
+        step("Redistribute all the routes (connected, static)")
+        input_dict_2_r1 = {
+            "r1": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2_r1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        input_dict_2_r2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2_r2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        input_dict_2_r3 = {
+            "r3": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2_r3)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("configure redistribute connected in Router BGP")
+
+        input_dict_2_r1 = {
+            "r1": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "connected"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2_r1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        input_dict_2_r3 = {
+            "r3": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "connected"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2_r3)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "connected"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Apply prefix list P1 on BGP neighbors 1 2 3 4 connected from " "frr r1")
+        # Configure prefix list to bgp neighbor
+        input_dict_4 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r1": {
+                                        "dest_link": {
+                                            "r2-link0": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link1": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link2": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link3": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Apply prefix list P2 on BGP nbrs 5 & 6 connected from FRR-2")
+        # Configure prefix list to bgp neighbor
+        input_dict_4 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "r2-link0": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link1": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link2": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link3": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        clear_bgp_and_verify(tgen, topo, "r2")
+
+        step(
+            "VM1 IPv4 and IPv6 Route which is denied using prefix list is "
+            "not present on FRR1 side routing table , also not able to "
+            "ping the routes show ip route"
+        )
+
+        dut = "r1"
+        protocol = "bgp"
+        ntwk_r2_vm1 = str(
+            ipaddress.ip_interface(
+                u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type])
+            ).network
+        )
+        input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+        result4 = verify_rib(
+            tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
+        )
+        assert result4 is not True, "Testcase {} : Failed , VM1 route is "
+        "not filtered out via prefix list. \n Error: {}".format(tc_name, result4)
+
+        step(
+            "VM4 and VM6 IPV4 and IPv6 address are present in local and "
+            "FRR2 routing table show ip bgp show ip route"
+        )
+
+        dut = "r2"
+        ntwk_r2_vm6 = str(
+            ipaddress.ip_interface(
+                u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type])
+            ).network
+        )
+        input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}}
+        result4 = verify_rib(tgen, addr_type, dut, input_dict)
+        assert result4 is True, "Testcase {} : Failed.\n Error: {}".format(
+            tc_name, result4
+        )
+
+        step("Remove prefix list from all the neighbors")
+        input_dict_4 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r1": {
+                                        "dest_link": {
+                                            "r2-link0": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link1": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link2": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link3": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_1_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        input_dict_4 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "r2-link0": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link1": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link2": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link3": {
+                                                "prefix_lists": [
+                                                    {
+                                                        "name": "pf_list_2_{}".format(
+                                                            addr_type
+                                                        ),
+                                                        "direction": "out",
+                                                        "delete": True,
+                                                    }
+                                                ]
+                                            },
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        clear_bgp_and_verify(tgen, topo, "r2")
+
+        step("Create RouteMap_1 with prefix list P1 and weight 50")
+        # Create route map
+        rmap_dict = {
+            "r2": {
+                "route_maps": {
+                    "rmap_pf_list_1_{}".format(addr_type): [
+                        {
+                            "action": "permit",
+                            "set": {"weight": 50},
+                            "match": {
+                                addr_type: {
+                                    "prefix_lists": "pf_list_1_{}".format(addr_type)
+                                }
+                            },
+                        }
+                    ]
+                }
+            }
+        }
+        result = create_route_maps(tgen, rmap_dict)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Create RouteMap_2 with prefix list P2 and weight 50")
+        # Create route map
+        rmap_dict = {
+            "r2": {
+                "route_maps": {
+                    "rmap_pf_list_2_{}".format(addr_type): [
+                        {
+                            "action": "permit",
+                            "set": {"weight": 50},
+                            "match": {
+                                addr_type: {
+                                    "prefix_lists": "pf_list_2_{}".format(addr_type)
+                                }
+                            },
+                        }
+                    ]
+                }
+            }
+        }
+        result = create_route_maps(tgen, rmap_dict)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Verify Route-map created verify using show route-map")
+        # verify rmap_pf_list_1 and rmap_pf_list_2 are present in router r2
+        input_dict = {
+            "r2": {
+                "route_maps": [
+                    "rmap_pf_list_1_{}".format(addr_type),
+                    "rmap_pf_list_2_{}".format(addr_type),
+                ]
+            }
+        }
+        result = verify_route_maps(tgen, input_dict, expected=False)
+        assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Apply policy RouteMap_1 nbrs 1 2 3 4 to FRR 1")
+        # Configure prefix list to bgp neighbor
+        input_dict_4 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r1": {
+                                        "dest_link": {
+                                            "r2-link0": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_1_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link1": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_1_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link2": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_1_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link3": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_1_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Apply policy RouteMap_2 nbrs 5 and 6 to FRR2")
+        # Configure prefix list to bgp neighbor
+        input_dict_4 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "r2-link0": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_2_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link1": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_2_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link2": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_2_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                            "r2-link3": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_pf_list_2_"
+                                                        "{}".format(addr_type),
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            },
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "After applying to BGP neighbors verify VM1 IPv4 and IPv6 Route"
+            " which is denied using prefix list is not present on FRR side"
+            " routing table , also not able to ping the routes show ip route"
+            " and VM4 and VM6 IPV4 and IPv6 address are present in local and"
+            " FRR routing table show ip bgp show ip route"
+        )
+
+        dut = "r1"
+        protocol = "bgp"
+        ntwk_r2_vm1 = str(
+            ipaddress.ip_interface(
+                u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type])
+            ).network
+        )
+        input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+        result4 = verify_rib(
+            tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
+        )
+        assert result4 is not True, "Testcase {} : Failed \n" "Error: {}".format(
+            tc_name, result4
+        )
+
+        step("vm4 should be present in FRR1")
+        dut = "r1"
+        ntwk_r2_vm1 = str(
+            ipaddress.ip_interface(
+                u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type])
+            ).network
+        )
+        input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+        result4 = verify_rib(tgen, addr_type, dut, input_dict)
+        assert result4 is True, "Testcase {} : Failed , VM1 route is "
+        "not filtered out via prefix list. \n Error: {}".format(tc_name, result4)
+
+        step("vm4 should be present in FRR2")
+        dut = "r2"
+        ntwk_r2_vm1 = str(
+            ipaddress.ip_interface(
+                u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type])
+            ).network
+        )
+        input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+        result4 = verify_rib(tgen, addr_type, dut, input_dict)
+        assert result4 is True, "Testcase {} : Failed , VM1 route is "
+        "not filtered out via prefix list. \n Error: {}".format(tc_name, result4)
+
+        dut = "r3"
+        protocol = "bgp"
+        ntwk_r2_vm6 = str(
+            ipaddress.ip_interface(
+                u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type])
+            ).network
+        )
+        input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}}
+        result4 = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol)
+        assert result4 is True, "Testcase {} : Failed.\n Error: {}".format(
+            tc_name, result4
+        )
+
+    write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index 4da5303641e86e21ec9ec4f1bda42fd5c5ac2596..94baf8438f8898e528dd56686d59564e3d67416c 100644 (file)
@@ -118,7 +118,12 @@ def test_zebra_netlink_batching():
     r1.vtysh_cmd("sharp install routes 2.1.3.7 nexthop 192.168.1.1 100")
     json_file = "{}/r1/v4_route.json".format(CWD)
     expected = json.loads(open(json_file).read())
-    test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expected,)
+    test_func = partial(
+        topotest.router_json_cmp,
+        r1,
+        "show ip route json",
+        expected,
+    )
     _, result = topotest.run_and_expect(test_func, None, count=2, wait=0.5)
     assertmsg = '"r1" JSON output mismatches'
     assert result is None, assertmsg
diff --git a/tests/topotests/zebra_rib/r1/iproute.ref b/tests/topotests/zebra_rib/r1/iproute.ref
new file mode 100644 (file)
index 0000000..b28182c
--- /dev/null
@@ -0,0 +1,512 @@
+4.5.1.0/24 via 192.168.210.2 dev r1-eth0 metric 4278198272 
+4.5.2.0/24 via 192.168.211.2 dev r1-eth1 metric 16777217 
+4.5.3.0/24 via 192.168.212.2 dev r1-eth2 metric 167772161 
+4.5.3.0/24 via 192.168.213.2 dev r1-eth3 metric 2684354561 
+10.0.0.0 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.1 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.2 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.3 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.4 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.5 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.6 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.7 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.8 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.9 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.10 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.11 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.12 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.13 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.14 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.15 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.16 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.17 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.18 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.19 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.20 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.21 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.22 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.23 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.24 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.25 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.26 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.27 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.28 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.29 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.30 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.31 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.32 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.33 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.34 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.35 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.36 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.37 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.38 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.39 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.40 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.41 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.42 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.43 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.45 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.46 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.47 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.48 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.49 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.50 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.51 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.52 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.53 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.54 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.55 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.56 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.57 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.58 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.59 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.60 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.61 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.62 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.63 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.64 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.65 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.66 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.67 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.68 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.69 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.70 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.71 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.72 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.73 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.74 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.75 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.76 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.77 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.78 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.79 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.80 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.81 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.82 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.83 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.84 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.85 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.86 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.87 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.88 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.89 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.90 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.91 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.92 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.93 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.94 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.95 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.96 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.97 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.98 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.99 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.100 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.101 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.102 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.103 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.104 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.105 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.106 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.107 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.108 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.109 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.110 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.111 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.112 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.113 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.114 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.115 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.116 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.117 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.118 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.119 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.120 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.121 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.122 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.123 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.124 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.125 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.126 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.127 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.128 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.129 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.130 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.131 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.132 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.133 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.134 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.135 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.136 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.137 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.138 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.139 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.140 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.141 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.142 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.143 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.144 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.145 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.146 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.147 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.148 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.149 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.150 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.151 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.152 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.153 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.154 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.155 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.156 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.157 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.158 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.159 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.160 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.161 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.162 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.163 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.164 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.165 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.166 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.167 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.168 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.169 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.170 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.171 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.172 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.173 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.174 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.175 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.176 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.177 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.178 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.179 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.180 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.181 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.182 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.183 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.184 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.185 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.186 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.187 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.188 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.189 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.190 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.191 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.192 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.193 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.194 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.195 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.196 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.197 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.198 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.199 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.200 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.201 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.202 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.203 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.204 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.205 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.206 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.207 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.208 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.209 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.210 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.211 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.212 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.213 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.214 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.215 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.216 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.217 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.218 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.219 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.220 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.221 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.222 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.223 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.224 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.225 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.226 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.227 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.228 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.229 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.230 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.231 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.232 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.233 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.234 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.235 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.236 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.237 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.238 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.239 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.240 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.241 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.242 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.243 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.244 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.245 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.246 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.247 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.248 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.249 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.250 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.251 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.252 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.253 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.254 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.0.255 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 
+10.0.1.0 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.1 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.2 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.3 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.4 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.5 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.6 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.7 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.8 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.9 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.10 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.11 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.12 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.13 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.14 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.15 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.16 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.17 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.18 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.19 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.20 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.21 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.22 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.23 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.24 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.25 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.26 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.27 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.28 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.29 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.30 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.31 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.32 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.33 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.34 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.35 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.36 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.37 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.38 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.39 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.40 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.41 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.42 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.43 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.44 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.45 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.46 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.47 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.48 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.49 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.50 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.51 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.52 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.53 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.54 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.55 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.56 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.57 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.58 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.59 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.60 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.61 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.62 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.63 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.64 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.65 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.66 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.67 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.68 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.69 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.70 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.71 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.72 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.73 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.74 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.75 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.76 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.77 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.78 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.79 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.80 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.81 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.82 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.83 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.84 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.85 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.86 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.87 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.88 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.89 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.90 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.91 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.92 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.93 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.94 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.95 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.96 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.97 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.98 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.99 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.100 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.101 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.102 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.103 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.104 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.105 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.106 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.107 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.108 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.109 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.110 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.111 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.112 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.113 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.114 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.115 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.116 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.117 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.118 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.119 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.120 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.121 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.122 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.123 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.124 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.125 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.126 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.127 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.128 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.129 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.130 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.131 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.132 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.133 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.134 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.135 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.136 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.137 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.138 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.139 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.140 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.141 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.142 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.143 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.144 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.145 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.146 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.147 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.148 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.149 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.150 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.151 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.152 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.153 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.154 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.155 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.156 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.157 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.158 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.159 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.160 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.161 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.162 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.163 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.164 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.165 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.166 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.167 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.168 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.169 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.170 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.171 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.172 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.173 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.174 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.175 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.176 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.177 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.178 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.179 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.180 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.181 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.182 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.183 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.184 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.185 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.186 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.187 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.188 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.189 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.190 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.191 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.192 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.193 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.194 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.195 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.196 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.197 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.198 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.199 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.200 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.201 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.202 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.203 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.204 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.205 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.206 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.207 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.208 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.209 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.210 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.211 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.212 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.213 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.214 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.215 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.216 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.217 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.218 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.219 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.220 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.221 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.222 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.223 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.224 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.225 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.226 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.227 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.228 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.229 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.230 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.231 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.232 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.233 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.234 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.235 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.236 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.237 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.238 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.239 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.240 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.241 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.242 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.0.1.243 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 
+10.100.100.100 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.215.1 metric 20 
+192.168.210.0/24 dev r1-eth0 proto XXXX scope link src 192.168.210.1 
+192.168.211.0/24 dev r1-eth1 proto XXXX scope link src 192.168.211.1 
+192.168.212.0/24 dev r1-eth2 proto XXXX scope link src 192.168.212.1 
+192.168.213.0/24 dev r1-eth3 proto XXXX scope link src 192.168.213.1 
+192.168.214.0/24 dev r1-eth4 proto XXXX scope link src 192.168.214.1 
+192.168.215.0/24 dev r1-eth5 proto XXXX scope link src 192.168.215.1 
+192.168.216.0/24 dev r1-eth6 proto XXXX scope link src 192.168.216.1 
+192.168.217.0/24 dev r1-eth7 proto XXXX scope link src 192.168.217.1 
diff --git a/tests/topotests/zebra_rib/r1/sharp_rmap.ref b/tests/topotests/zebra_rib/r1/sharp_rmap.ref
new file mode 100644 (file)
index 0000000..47a9eb6
--- /dev/null
@@ -0,0 +1,17 @@
+ZEBRA:
+route-map: sharp Invoked: 500 Optimization: enabled Processed Change: false
+ permit, sequence 10 Invoked 244
+  Match clauses:
+    ip address 10
+  Set clauses:
+    src 192.168.214.1
+  Call clause:
+  Action:
+    Exit routemap
+ permit, sequence 20 Invoked 256
+  Match clauses:
+  Set clauses:
+    src 192.168.213.1
+  Call clause:
+  Action:
+    Exit routemap
diff --git a/tests/topotests/zebra_rib/r1/static_rmap.ref b/tests/topotests/zebra_rib/r1/static_rmap.ref
new file mode 100644 (file)
index 0000000..2de98bd
--- /dev/null
@@ -0,0 +1,9 @@
+ZEBRA:
+route-map: static Invoked: 2 Optimization: enabled Processed Change: false
+ permit, sequence 10 Invoked 2
+  Match clauses:
+  Set clauses:
+    src 192.168.215.1
+  Call clause:
+  Action:
+    Exit routemap
index ef4b597206951aada37b8b31dc1f3abd301c0441..daf8f7be20f6ac19aceaf38ea506b2fd4c5536a7 100644 (file)
@@ -41,6 +41,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 time import sleep
 
 # Required to instantiate the topology builder class.
 from mininet.topo import Topo
@@ -75,8 +76,9 @@ def setup_module(mod):
     router_list = tgen.routers()
     for rname, router in router_list.items():
         router.load_config(
-            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
-        )
+            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)))
 
     # Initialize all routers.
     tgen.start_router()
@@ -157,6 +159,111 @@ def test_zebra_kernel_override():
     _, result = topotest.run_and_expect(test_func, None, count=2, wait=0.5)
     assert result is None, '"r1" JSON output mismatches'
 
+def test_route_map_usage():
+    "Test that FRR only reruns over routes associated with the routemap"
+    logger.info("Test that FRR runs on selected re's on route-map changes")
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip("Skipped because of previous test failure")
+
+    thisDir = os.path.dirname(os.path.realpath(__file__))
+
+    r1 = tgen.gears["r1"]
+    # set the delay timer to 1 to improve test coverage (HA)
+    r1.vtysh_cmd("conf\nzebra route-map delay-timer 1")
+    r1.vtysh_cmd("conf\nroute-map static permit 10\nset src 192.168.215.1")
+    r1.vtysh_cmd("conf\naccess-list 5 seq 5 permit 10.0.0.44/32")
+    r1.vtysh_cmd("conf\naccess-list 10 seq 5 permit 10.0.1.0/24")
+    r1.vtysh_cmd("conf\nroute-map sharp permit 10\nmatch ip address 10\nset src 192.168.214.1")
+    r1.vtysh_cmd("conf\nroute-map sharp permit 20\nset src 192.168.213.1")
+    r1.vtysh_cmd("conf\nip protocol static route-map static")
+    r1.vtysh_cmd("conf\nip protocol sharp route-map sharp")
+    sleep(4)
+    r1.vtysh_cmd("conf\nip route 10.100.100.100/32 192.168.216.3")
+    r1.vtysh_cmd("conf\nip route 10.100.100.101/32 10.0.0.44")
+    r1.vtysh_cmd("sharp install route 10.0.0.0 nexthop 192.168.216.3 500")
+    sleep(4)
+
+    static_rmapfile = "%s/r1/static_rmap.ref" % (thisDir)
+    expected = open(static_rmapfile).read().rstrip()
+    expected = ('\n'.join(expected.splitlines()) + '\n').rstrip()
+    actual = r1.vtysh_cmd("show route-map static")
+    actual = ('\n'.join(actual.splitlines()) + '\n').rstrip()
+    logger.info("Does the show route-map static command run the correct number of times")
+
+    diff = topotest.get_textdiff(actual, expected,
+                                 title1 = "Actual Route-map output",
+                                 title2 = "Expected Route-map output")
+    if diff:
+        logger.info("Actual:")
+        logger.info(actual)
+        logger.info("Expected:")
+        logger.info(expected)
+        srun = r1.vtysh_cmd("show run")
+        srun = ('\n'.join(srun.splitlines()) + '\n').rstrip()
+        logger.info("Show run")
+        logger.info(srun)
+        assert 0, "r1 static route processing:\n"
+
+    sharp_rmapfile = "%s/r1/sharp_rmap.ref" % (thisDir)
+    expected = open(sharp_rmapfile).read().rstrip()
+    expected = ('\n'.join(expected.splitlines()) + '\n').rstrip()
+    actual = r1.vtysh_cmd("show route-map sharp")
+    actual = ('\n'.join(actual.splitlines()) + '\n').rstrip()
+    logger.info("Does the show route-map sharp command run the correct number of times")
+
+    diff = topotest.get_textdiff(actual, expected,
+                                 title1 = "Actual Route-map output",
+                                 title2 = "Expected Route-map output")
+    if diff:
+        logger.info("Actual:")
+        logger.info(actual)
+        logger.info("Expected:")
+        logger.info(expected)
+        srun = r1.vtysh_cmd("show run")
+        srun = ('\n'.join(srun.splitlines()) + '\n').rstrip()
+        logger.info("Show run:")
+        logger.info(srun)
+        assert 0, "r1 sharp route-map processing:\n"
+
+    logger.info("Add a extension to the static route-map to see the static route go away")
+    r1.vtysh_cmd("conf\nroute-map sharp deny 5\nmatch ip address 5")
+    sleep(2)
+    # we are only checking the kernel here as that this will give us the implied
+    # testing of both the route-map and staticd withdrawing the route
+    # let's spot check that the routes were installed correctly
+    # in the kernel
+    logger.info("Test that the routes installed are correct")
+    sharp_ipfile = "%s/r1/iproute.ref" % (thisDir)
+    expected = open(sharp_ipfile).read().rstrip()
+    expected = ('\n'.join(expected.splitlines()) + '\n').rstrip()
+    actual = r1.run("ip route show")
+    actual = ('\n'.join(actual.splitlines()) + '\n').rstrip()
+    actual = re.sub(r" nhid [0-9][0-9]", "", actual)
+    actual = re.sub(r" proto sharp", " proto XXXX", actual)
+    actual = re.sub(r" proto static", " proto XXXX", actual)
+    actual = re.sub(r" proto 194", " proto XXXX", actual)
+    actual = re.sub(r" proto 196", " proto XXXX", actual)
+    actual = re.sub(r" proto kernel", " proto XXXX", actual)
+    actual = re.sub(r" proto 2", " proto XXXX", actual)
+    # Some platforms have double spaces?  Why??????
+    actual = re.sub(r"  proto XXXX  ", " proto XXXX ", actual)
+    actual = re.sub(r"  metric", " metric", actual)
+    actual = re.sub(r" link  ", " link ", actual)
+    diff = topotest.get_textdiff(actual, expected,
+                                 title1 = "Actual ip route show",
+                                 title2 = "Expected ip route show")
+
+    if diff:
+        logger.info("Actual:")
+        logger.info(actual)
+        logger.info("Expected:")
+        logger.info(expected)
+        srun = r1.vtysh_cmd("show run")
+        srun = ('\n'.join(srun.splitlines()) + '\n').rstrip()
+        logger.info("Show run:")
+        logger.info(srun)
+        assert 0, "r1 ip route show is not correct:"
 
 def test_memory_leak():
     "Run the memory leak test and report results."
diff --git a/tests/zebra/test_lm_plugin.c b/tests/zebra/test_lm_plugin.c
new file mode 100644 (file)
index 0000000..4a9344f
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Label Manager tests.
+ * Copyright (C) 2020 Volta Networks
+ *                    Patrick Ruddy
+ *
+ * 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 "zebra/zapi_msg.h"
+#include "zebra/label_manager.h"
+
+/* shim out unused functions/variables to allow the lablemanager to compile*/
+DEFINE_KOOH(zserv_client_close, (struct zserv * client), (client));
+unsigned long zebra_debug_packet = 0;
+struct zserv *zserv_find_client_session(uint8_t proto, unsigned short instance,
+                                       uint32_t session_id)
+{
+       return NULL;
+}
+
+int zsend_label_manager_connect_response(struct zserv *client, vrf_id_t vrf_id,
+                                        unsigned short result)
+{
+       return 0;
+}
+
+int zsend_assign_label_chunk_response(struct zserv *client, vrf_id_t vrf_id,
+                                     struct label_manager_chunk *lmc)
+{
+       return 0;
+}
+
+
+static int test_client_connect(struct zserv *client, vrf_id_t vrf_id)
+{
+       return 0;
+}
+
+static int test_client_disconnect(struct zserv *client)
+{
+       return 0;
+}
+
+/* external test hook functions */
+static int lm_get_chunk_pi(struct label_manager_chunk **lmc,
+                          struct zserv *client, uint8_t keep, uint32_t size,
+                          uint32_t base, vrf_id_t vrf_id)
+{
+       if (base == 0)
+               *lmc = create_label_chunk(10, 55, 0, 1, 50, 50 + size);
+       else
+               *lmc = assign_label_chunk(10, 55, 0, 1, size, base);
+
+       return 0;
+}
+
+static int lm_release_chunk_pi(struct zserv *client, uint32_t start,
+                              uint32_t end)
+{
+       return release_label_chunk(client->proto, client->instance,
+                                  client->session_id, start, end);
+}
+
+
+/* use external allocations */
+static void lp_plugin_init()
+{
+       /* register our own hooks */
+       hook_register(lm_client_connect, test_client_connect);
+       hook_register(lm_client_disconnect, test_client_disconnect);
+       hook_register(lm_get_chunk, lm_get_chunk_pi);
+       hook_register(lm_release_chunk, lm_release_chunk_pi);
+}
+
+static void lp_plugin_cleanup()
+{
+       /* register our own hooks */
+       hook_unregister(lm_client_connect, test_client_connect);
+       hook_unregister(lm_client_disconnect, test_client_disconnect);
+       hook_unregister(lm_get_chunk, lm_get_chunk_pi);
+       hook_unregister(lm_release_chunk, lm_release_chunk_pi);
+}
+
+
+/* tests */
+
+static void test_lp_plugin()
+{
+       struct label_manager_chunk *lmc;
+
+       lmc = assign_label_chunk(10, 55, 0, 1, 50, 0);
+       fprintf(stdout,
+               "chunk: start %u end %u proto %u instance %u session %u keep %s\n",
+               lmc->start, lmc->end, lmc->proto, lmc->instance,
+               lmc->session_id, lmc->keep ? "yes" : "no");
+       delete_label_chunk(lmc);
+
+       lmc = assign_label_chunk(10, 55, 0, 1, 50, 100);
+       fprintf(stdout,
+               "chunk: start %u end %u proto %u instance %u session %u keep %s\n",
+               lmc->start, lmc->end, lmc->proto, lmc->instance,
+               lmc->session_id, lmc->keep ? "yes" : "no");
+       release_label_chunk(10, 55, 0, lmc->start, lmc->end);
+}
+
+int main(int argc, char **argv)
+{
+       /* set up label manager and release it's hooks */
+       label_manager_init();
+       lm_hooks_unregister();
+
+       /* test plugin */
+       lp_plugin_init();
+       test_lp_plugin();
+       lp_plugin_cleanup();
+
+       /* this keeps the compiler happy */
+       hook_call(zserv_client_close, NULL);
+       return 0;
+}
diff --git a/tests/zebra/test_lm_plugin.py b/tests/zebra/test_lm_plugin.py
new file mode 100644 (file)
index 0000000..bf4f3ce
--- /dev/null
@@ -0,0 +1,5 @@
+import frrtest
+
+
+class TestLmplugin(frrtest.TestRefOut):
+    program = "./test_lm_plugin"
diff --git a/tests/zebra/test_lm_plugin.refout b/tests/zebra/test_lm_plugin.refout
new file mode 100644 (file)
index 0000000..35824f1
--- /dev/null
@@ -0,0 +1,2 @@
+chunk: start 16 end 65 proto 10 instance 55 session 0 keep yes
+chunk: start 100 end 149 proto 10 instance 55 session 0 keep yes
index 11f88e710120485c74dd9439c2722b0bf7a5ec83..087c35981d3efe508ec91de192f4310adb9fd0b9 100644 (file)
@@ -8,17 +8,17 @@
 PROC_NAME:bgp
 CMD_LIST_START
 show bgp summary
-show ip bgp
-show ip bgp neighbors
-show ip bgp summary
-show ip bgp statistics
+show bgp ipv4 uni
+show bgp ipv4 neighbors
+show bgp ipv4 summary
+show bgp ipv4 statistics
 
-show ip bgp update-groups advertise-queue
-show ip bgp update-groups advertised-routes
-show ip bgp update-groups packet-queue
-show ip bgp update-groups statistics
-show ip bgp peer-group
-show ip bgp memory
+show bgp ipv4 update-groups advertise-queue
+show bgp ipv4 update-groups advertised-routes
+show bgp ipv4 update-groups packet-queue
+show bgp ipv4 update-groups statistics
+show bgp peer-group
+show bgp memory
 
 show bgp ipv6
 show bgp ipv6 neighbors
@@ -27,8 +27,9 @@ show bgp ipv6 update-groups advertise-queue
 show bgp ipv6 update-groups advertised-routes
 show bgp ipv6 update-groups packet-queue
 show bgp ipv6 update-groups statistics
-show ip bgp statistics
+show bgp ipv6 statistics
 show bgp martian next-hop
+show bgp nexthop
 
 show bgp evpn route
 CMD_LIST_END
@@ -38,13 +39,15 @@ PROC_NAME:zebra
 CMD_LIST_START
 show zebra
 show zebra client summary
+show zebra router table summary
 show ip nht vrf all
+show ipv6 nht vrf all
+show nexthop-group rib
 show route-map
 show memory
 show interface vrf all
 show vrf
 show zebra fpm stats
-show error all
 show work-queues
 show debugging hashtable
 show running-config
index 951383beb260f68c4d9baa5b11bc22808ecb47c4..0aa5f1e51668f90ab46a282e9e21f042d978cf63 100755 (executable)
@@ -222,6 +222,29 @@ ip forwarding
             self.dlines[ligne] = True
 
 
+def get_normalized_es_id(line):
+    """
+    The es-id or es-sys-mac need to be converted to lower case
+    """
+    sub_strs = ["evpn mh es-id", "evpn mh es-sys-mac"]
+    for sub_str in sub_strs:
+        obj = re.match(sub_str + " (?P<esi>\S*)", line)
+        if obj:
+            line = "%s %s" % (sub_str, obj.group("esi").lower())
+            break
+    return line
+
+
+def get_normalized_mac_ip_line(line):
+    if line.startswith("evpn mh es"):
+        return get_normalized_es_id(line)
+
+    if not "ipv6 add" in line:
+        return get_normalized_ipv6_line(line)
+
+    return line
+
+
 class Config(object):
 
     """
@@ -251,11 +274,10 @@ class Config(object):
             # Compress duplicate whitespaces
             line = " ".join(line.split())
 
-            if ":" in line and not "ipv6 add":
-                qv6_line = get_normalized_ipv6_line(line)
-                self.lines.append(qv6_line)
-            else:
-                self.lines.append(line)
+            if ":" in line:
+                line = get_normalized_mac_ip_line(line)
+
+            self.lines.append(line)
 
         self.load_contexts()
 
@@ -531,6 +553,7 @@ end
             "dump ",
             "enable ",
             "frr ",
+            "fpm ",
             "hostname ",
             "ip ",
             "ipv6 ",
@@ -607,6 +630,22 @@ end
                 ctx_keys = []
                 current_context_lines = []
 
+            elif (
+                line == "exit"
+                and len(ctx_keys) > 1
+                and ctx_keys[0].startswith("segment-routing")
+            ):
+                self.save_contexts(ctx_keys, current_context_lines)
+
+                # Start a new context
+                ctx_keys = ctx_keys[:-1]
+                current_context_lines = []
+                log.debug(
+                    "LINE %-50s: popping segment routing sub-context to ctx%-50s",
+                    line,
+                    ctx_keys,
+                )
+
             elif line in ["exit-address-family", "exit", "exit-vnc"]:
                 # if this exit is for address-family ipv4 unicast, ignore the pop
                 if main_ctx_key:
@@ -646,6 +685,7 @@ end
                 current_context_lines = []
                 new_ctx = False
                 log.debug("LINE %-50s: entering new context, %-50s", line, ctx_keys)
+
             elif (
                 line.startswith("address-family ")
                 or line.startswith("vnc defaults")
@@ -708,6 +748,140 @@ end
                 )
                 ctx_keys.append(line)
 
+            elif (
+                line.startswith("traffic-eng")
+                and len(ctx_keys) == 1
+                and ctx_keys[0].startswith("segment-routing")
+            ):
+
+                # Save old context first
+                self.save_contexts(ctx_keys, current_context_lines)
+                current_context_lines = []
+                log.debug(
+                    "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
+                    line,
+                )
+                ctx_keys.append(line)
+
+            elif (
+                line.startswith("segment-list ")
+                and len(ctx_keys) == 2
+                and ctx_keys[0].startswith("segment-routing")
+                and ctx_keys[1].startswith("traffic-eng")
+            ):
+
+                # Save old context first
+                self.save_contexts(ctx_keys, current_context_lines)
+                current_context_lines = []
+                log.debug(
+                    "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
+                    line,
+                )
+                ctx_keys.append(line)
+
+            elif (
+                line.startswith("policy ")
+                and len(ctx_keys) == 2
+                and ctx_keys[0].startswith("segment-routing")
+                and ctx_keys[1].startswith("traffic-eng")
+            ):
+
+                # Save old context first
+                self.save_contexts(ctx_keys, current_context_lines)
+                current_context_lines = []
+                log.debug(
+                    "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
+                    line,
+                )
+                ctx_keys.append(line)
+
+            elif (
+                line.startswith("candidate-path ")
+                and line.endswith(" dynamic")
+                and len(ctx_keys) == 3
+                and ctx_keys[0].startswith("segment-routing")
+                and ctx_keys[1].startswith("traffic-eng")
+                and ctx_keys[2].startswith("policy")
+            ):
+
+                # Save old context first
+                self.save_contexts(ctx_keys, current_context_lines)
+                current_context_lines = []
+                main_ctx_key = copy.deepcopy(ctx_keys)
+                log.debug(
+                    "LINE %-50s: entering candidate-path sub-context, append to ctx_keys",
+                    line,
+                )
+                ctx_keys.append(line)
+
+            elif (
+                line.startswith("pcep")
+                and len(ctx_keys) == 2
+                and ctx_keys[0].startswith("segment-routing")
+                and ctx_keys[1].startswith("traffic-eng")
+            ):
+
+                # Save old context first
+                self.save_contexts(ctx_keys, current_context_lines)
+                current_context_lines = []
+                main_ctx_key = copy.deepcopy(ctx_keys)
+                log.debug(
+                    "LINE %-50s: entering pcep sub-context, append to ctx_keys", line
+                )
+                ctx_keys.append(line)
+
+            elif (
+                line.startswith("pce-config ")
+                and len(ctx_keys) == 3
+                and ctx_keys[0].startswith("segment-routing")
+                and ctx_keys[1].startswith("traffic-eng")
+                and ctx_keys[2].startswith("pcep")
+            ):
+
+                # Save old context first
+                self.save_contexts(ctx_keys, current_context_lines)
+                current_context_lines = []
+                main_ctx_key = copy.deepcopy(ctx_keys)
+                log.debug(
+                    "LINE %-50s: entering pce-config sub-context, append to ctx_keys",
+                    line,
+                )
+                ctx_keys.append(line)
+
+            elif (
+                line.startswith("pce ")
+                and len(ctx_keys) == 3
+                and ctx_keys[0].startswith("segment-routing")
+                and ctx_keys[1].startswith("traffic-eng")
+                and ctx_keys[2].startswith("pcep")
+            ):
+
+                # Save old context first
+                self.save_contexts(ctx_keys, current_context_lines)
+                current_context_lines = []
+                main_ctx_key = copy.deepcopy(ctx_keys)
+                log.debug(
+                    "LINE %-50s: entering pce sub-context, append to ctx_keys", line
+                )
+                ctx_keys.append(line)
+
+            elif (
+                line.startswith("pcc")
+                and len(ctx_keys) == 3
+                and ctx_keys[0].startswith("segment-routing")
+                and ctx_keys[1].startswith("traffic-eng")
+                and ctx_keys[2].startswith("pcep")
+            ):
+
+                # Save old context first
+                self.save_contexts(ctx_keys, current_context_lines)
+                current_context_lines = []
+                main_ctx_key = copy.deepcopy(ctx_keys)
+                log.debug(
+                    "LINE %-50s: entering pcc sub-context, append to ctx_keys", line
+                )
+                ctx_keys.append(line)
+
             else:
                 # Continuing in an existing context, add non-commented lines to it
                 current_context_lines.append(line)
@@ -1064,30 +1238,44 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
                     lines_to_add_to_del.append((ctx[0], None))
 
         """
-        ip/ipv6 prefix-list can be specified without a seq number. However,
-        the running config always adds 'seq x', where x is a number incremented
-        by 5 for every element, to the prefix list. So, ignore such lines as
-        well. Sample prefix-list lines:
+        ip/ipv6 prefix-lists and access-lists can be specified without a seq number.
+        However, the running config always adds 'seq x', where x is a number
+        incremented by 5 for every element of the prefix/access list.
+        So, ignore such lines as well. Sample prefix-list and acces-list lines:
              ip prefix-list PR-TABLE-2 seq 5 permit 20.8.2.0/24 le 32
              ip prefix-list PR-TABLE-2 seq 10 permit 20.8.2.0/24 le 32
              ipv6 prefix-list vrfdev6-12 permit 2000:9:2::/64 gt 64
+             access-list FOO seq 5 permit 2.2.2.2/32
+             ipv6 access-list BAR seq 5 permit 2:2:2::2/128
         """
-        re_ip_pfxlst = re.search(
-            "^(ip|ipv6)(\s+prefix-list\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
+        re_acl_pfxlst = re.search(
+            "^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
             ctx_keys[0],
         )
-        if re_ip_pfxlst:
+        if re_acl_pfxlst:
+            found = False
             tmpline = (
-                re_ip_pfxlst.group(1)
-                + re_ip_pfxlst.group(2)
-                + re_ip_pfxlst.group(3)
-                + re_ip_pfxlst.group(5)
-                + re_ip_pfxlst.group(6)
+                re_acl_pfxlst.group(1)
+                + re_acl_pfxlst.group(2)
+                + re_acl_pfxlst.group(3)
+                + re_acl_pfxlst.group(5)
+                + re_acl_pfxlst.group(6)
             )
             for ctx in lines_to_add:
                 if ctx[0][0] == tmpline:
                     lines_to_del_to_del.append((ctx_keys, None))
                     lines_to_add_to_del.append(((tmpline,), None))
+                    found = True
+            """
+            If prefix-lists or access-lists are being deleted and
+            not added (see comment above), add command with 'no' to
+            lines_to_add and remove from lines_to_del to improve
+            scaling performance.
+            """
+            if found is False:
+                add_cmd = ("no " + ctx_keys[0],)
+                lines_to_add.append((add_cmd, None))
+                lines_to_del_to_del.append((ctx_keys, None))
 
         if (
             len(ctx_keys) == 3
@@ -1225,6 +1413,11 @@ def compare_context_objects(newconf, running):
     # Compare the two Config objects to find the lines that we need to add/del
     lines_to_add = []
     lines_to_del = []
+    pollist_to_del = []
+    seglist_to_del = []
+    pceconf_to_del = []
+    pcclist_to_del = []
+    candidates_to_add = []
     delete_bgpd = False
 
     # Find contexts that are in newconf but not in running
@@ -1280,14 +1473,9 @@ def compare_context_objects(newconf, running):
             # doing vtysh -c inefficient (and can time out.)  For
             # these commands, instead of adding them to lines_to_del,
             # add the "no " version to lines_to_add.
-            elif (
-                running_ctx_keys[0].startswith("ip route")
-                or running_ctx_keys[0].startswith("ipv6 route")
-                or running_ctx_keys[0].startswith("access-list")
-                or running_ctx_keys[0].startswith("ipv6 access-list")
-                or running_ctx_keys[0].startswith("ip prefix-list")
-                or running_ctx_keys[0].startswith("ipv6 prefix-list")
-            ):
+            elif running_ctx_keys[0].startswith("ip route") or running_ctx_keys[
+                0
+            ].startswith("ipv6 route"):
                 add_cmd = ("no " + running_ctx_keys[0],)
                 lines_to_add.append((add_cmd, None))
 
@@ -1301,6 +1489,65 @@ def compare_context_objects(newconf, running):
             ):
                 continue
 
+            # same thing for a pseudowire sub-context inside an l2vpn context
+            elif (
+                len(running_ctx_keys) > 1
+                and running_ctx_keys[0].startswith("l2vpn")
+                and running_ctx_keys[1].startswith("member pseudowire")
+                and (running_ctx_keys[:1], None) in lines_to_del
+            ):
+                continue
+
+            # Segment routing and traffic engineering never need to be deleted
+            elif (
+                running_ctx_keys[0].startswith("segment-routing")
+                and len(running_ctx_keys) < 3
+            ):
+                continue
+
+            # Neither the pcep command
+            elif (
+                len(running_ctx_keys) == 3
+                and running_ctx_keys[0].startswith("segment-routing")
+                and running_ctx_keys[2].startswith("pcep")
+            ):
+                continue
+
+            # Segment lists can only be deleted after we removed all the candidate paths that
+            # use them, so add them to a separate array that is going to be appended at the end
+            elif (
+                len(running_ctx_keys) == 3
+                and running_ctx_keys[0].startswith("segment-routing")
+                and running_ctx_keys[2].startswith("segment-list")
+            ):
+                seglist_to_del.append((running_ctx_keys, None))
+
+            # Policies must be deleted after there candidate path, to be sure
+            # we add them to a separate array that is going to be appended at the end
+            elif (
+                len(running_ctx_keys) == 3
+                and running_ctx_keys[0].startswith("segment-routing")
+                and running_ctx_keys[2].startswith("policy")
+            ):
+                pollist_to_del.append((running_ctx_keys, None))
+
+            # pce-config must be deleted after the pce, to be sure we add them
+            # to a separate array that is going to be appended at the end
+            elif (
+                len(running_ctx_keys) >= 4
+                and running_ctx_keys[0].startswith("segment-routing")
+                and running_ctx_keys[3].startswith("pce-config")
+            ):
+                pceconf_to_del.append((running_ctx_keys, None))
+
+            # pcc must be deleted after the pce and pce-config too
+            elif (
+                len(running_ctx_keys) >= 4
+                and running_ctx_keys[0].startswith("segment-routing")
+                and running_ctx_keys[3].startswith("pcc")
+            ):
+                pcclist_to_del.append((running_ctx_keys, None))
+
             # Non-global context
             elif running_ctx_keys and not any(
                 "address-family" in key for key in running_ctx_keys
@@ -1315,6 +1562,22 @@ def compare_context_objects(newconf, running):
                 for line in running_ctx.lines:
                     lines_to_del.append((running_ctx_keys, line))
 
+    # if we have some policies commands to delete, append them to lines_to_del
+    if len(pollist_to_del) > 0:
+        lines_to_del.extend(pollist_to_del)
+
+    # if we have some segment list commands to delete, append them to lines_to_del
+    if len(seglist_to_del) > 0:
+        lines_to_del.extend(seglist_to_del)
+
+    # if we have some pce list commands to delete, append them to lines_to_del
+    if len(pceconf_to_del) > 0:
+        lines_to_del.extend(pceconf_to_del)
+
+    # if we have some pcc list commands to delete, append them to lines_to_del
+    if len(pcclist_to_del) > 0:
+        lines_to_del.extend(pcclist_to_del)
+
     # Find the lines within each context to add
     # Find the lines within each context to del
     for (newconf_ctx_keys, newconf_ctx) in iteritems(newconf.contexts):
@@ -1324,7 +1587,19 @@ def compare_context_objects(newconf, running):
 
             for line in newconf_ctx.lines:
                 if line not in running_ctx.dlines:
-                    lines_to_add.append((newconf_ctx_keys, line))
+
+                    # candidate paths can only be added after the policy and segment list,
+                    # so add them to a separate array that is going to be appended at the end
+                    if (
+                        len(newconf_ctx_keys) == 3
+                        and newconf_ctx_keys[0].startswith("segment-routing")
+                        and newconf_ctx_keys[2].startswith("policy ")
+                        and line.startswith("candidate-path ")
+                    ):
+                        candidates_to_add.append((newconf_ctx_keys, line))
+
+                    else:
+                        lines_to_add.append((newconf_ctx_keys, line))
 
             for line in running_ctx.lines:
                 if line not in newconf_ctx.dlines:
@@ -1333,10 +1608,27 @@ def compare_context_objects(newconf, running):
     for (newconf_ctx_keys, newconf_ctx) in iteritems(newconf.contexts):
 
         if newconf_ctx_keys not in running.contexts:
-            lines_to_add.append((newconf_ctx_keys, None))
 
-            for line in newconf_ctx.lines:
-                lines_to_add.append((newconf_ctx_keys, line))
+            # candidate paths can only be added after the policy and segment list,
+            # so add them to a separate array that is going to be appended at the end
+            if (
+                len(newconf_ctx_keys) == 4
+                and newconf_ctx_keys[0].startswith("segment-routing")
+                and newconf_ctx_keys[3].startswith("candidate-path")
+            ):
+                candidates_to_add.append((newconf_ctx_keys, None))
+                for line in newconf_ctx.lines:
+                    candidates_to_add.append((newconf_ctx_keys, line))
+
+            else:
+                lines_to_add.append((newconf_ctx_keys, None))
+
+                for line in newconf_ctx.lines:
+                    lines_to_add.append((newconf_ctx_keys, line))
+
+    # if we have some candidate paths commands to add, append them to lines_to_add
+    if len(candidates_to_add) > 0:
+        lines_to_add.extend(candidates_to_add)
 
     (lines_to_add, lines_to_del) = check_for_exit_vrf(lines_to_add, lines_to_del)
     (lines_to_add, lines_to_del) = ignore_delete_re_add_lines(
@@ -1498,10 +1790,12 @@ if __name__ == "__main__":
         "staticd",
         "vrrpd",
         "ldpd",
+        "pathd",
+        "bfdd",
     ]:
-        log.error(
-            "Daemon %s is not a valid option for 'show running-config'" % args.daemon
-        )
+        msg = "Daemon %s is not a valid option for 'show running-config'" % args.daemon
+        print(msg)
+        log.error(msg)
         sys.exit(1)
 
     vtysh = Vtysh(args.bindir, args.confdir, args.vty_socket, args.pathspace)
index b860797d5b0f04e5d592c5e9eb0f1bd5a6e43903..889c075f81d4ec0944cfee02beeda1a13dc46703 100755 (executable)
@@ -27,7 +27,7 @@ FRR_DEFAULT_PROFILE="@DFLT_NAME@" # traditional / datacenter
 # Local Daemon selection may be done by using /etc/frr/daemons.
 # See /usr/share/doc/frr/README.Debian.gz for further information.
 # Keep zebra first and do not list watchfrr!
-DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd"
+DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
 MAX_INSTANCES=5
 RELOAD_SCRIPT="$D_PATH/frr-reload.py"
 
index 312ee88bf4571d537b50a9b41804546a70077630..3dbc6a1b43b9c7bd8472015b49a1de6ef760f944 100644 (file)
@@ -59,6 +59,9 @@ 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 u+x "$1"
+       fi
 }
 
 vtysh_b () {
index 37a1e4a624bcdf98206dd83e4063e8af21740576..385d4435712728f281aadb0aed3ce578aec283b0 100644 (file)
@@ -179,14 +179,13 @@ void vrrp_zebra_radv_set(struct vrrp_router *r, bool enable)
                                        enable, VRRP_RADV_INT);
 }
 
-int vrrp_zclient_send_interface_protodown(struct interface *ifp, bool down)
+void vrrp_zclient_send_interface_protodown(struct interface *ifp, bool down)
 {
        DEBUGD(&vrrp_dbg_zebra,
               VRRP_LOGPFX "Requesting Zebra to set %s protodown %s", ifp->name,
               down ? "on" : "off");
 
-       return zclient_send_interface_protodown(zclient, ifp->vrf_id, ifp,
-                                               down);
+       zclient_send_interface_protodown(zclient, ifp->vrf_id, ifp, down);
 }
 
 void vrrp_zebra_init(void)
index 02d7055b8600ed8e13c091bf6c34872bcee2ab6b..c09943dcef9d32cc277a75eb8fe03a5a62203c85 100644 (file)
@@ -26,8 +26,8 @@
 
 extern void vrrp_zebra_init(void);
 extern void vrrp_zebra_radv_set(struct vrrp_router *r, bool enable);
-extern int vrrp_zclient_send_interface_protodown(struct interface *ifp,
-                                                bool down);
+extern void vrrp_zclient_send_interface_protodown(struct interface *ifp,
+                                                 bool down);
 
 extern int vrrp_ifp_create(struct interface *ifp);
 extern int vrrp_ifp_up(struct interface *ifp);
index 1e4439d274d60402a0367d06b03fbae1bcd20d07..86861b0390ed9ca7af49cb9141ca92a90bc4447e 100644 (file)
@@ -33,8 +33,9 @@ BUILT_SOURCES += vtysh/vtysh_daemons.h
 # force vtysh_daemons.h
 $(vtysh_vtysh_OBJECTS): vtysh/vtysh_daemons.h
 
+CLEANFILES += vtysh/vtysh_daemons.h
 vtysh/vtysh_daemons.h:
-       $(PERL) vtysh/daemons.pl $(vtysh_daemons) > 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))
index 8a1e71a37dc6bb8e57b902bf45f4a362034eee55..a6f9f39a4cf37fe6e12513d6c94c8b3c3fb30bd9 100644 (file)
@@ -139,6 +139,7 @@ struct vtysh_client vtysh_client[] = {
        {.fd = -1, .name = "staticd", .flag = VTYSH_STATICD, .next = NULL},
        {.fd = -1, .name = "bfdd", .flag = VTYSH_BFDD, .next = NULL},
        {.fd = -1, .name = "vrrpd", .flag = VTYSH_VRRPD, .next = NULL},
+       {.fd = -1, .name = "pathd", .flag = VTYSH_PATHD, .next = NULL},
 };
 
 /* Searches for client by name, returns index */
@@ -538,6 +539,15 @@ static int vtysh_execute_func(const char *line, int pager)
                            || saved_node == LDP_IPV6_IFACE_NODE)
                           && (tried == 1)) {
                        vtysh_execute("exit");
+               } else if ((saved_node == SR_SEGMENT_LIST_NODE
+                           || saved_node == SR_POLICY_NODE
+                           || saved_node == SR_CANDIDATE_DYN_NODE
+                           || saved_node == PCEP_NODE
+                           || saved_node == PCEP_PCE_CONFIG_NODE
+                           || saved_node == PCEP_PCE_NODE
+                           || saved_node == PCEP_PCC_NODE)
+                          && (tried > 0)) {
+                       vtysh_execute("exit");
                } else if (tried) {
                        vtysh_execute("end");
                        vtysh_execute("configure");
@@ -689,6 +699,7 @@ int vtysh_mark_file(const char *filename)
        int ret;
        vector vline;
        int tried = 0;
+       bool ending;
        const struct cmd_element *cmd;
        int saved_ret, prev_node;
        int lineno = 0;
@@ -740,6 +751,12 @@ int vtysh_mark_file(const char *filename)
                                vty->node = LDP_L2VPN_NODE;
                        }
                        break;
+               case SR_CANDIDATE_DYN_NODE:
+                       if (strncmp(vty_buf_copy, "  ", 2)) {
+                               vty_out(vty, " exit\n");
+                               vty->node = SR_POLICY_NODE;
+                       }
+                       break;
                default:
                        break;
                }
@@ -812,6 +829,31 @@ int vtysh_mark_file(const char *filename)
                        } else if ((prev_node == BFD_PEER_NODE)
                                   && (tried == 1)) {
                                vty_out(vty, "exit\n");
+                       } else if (((prev_node == SEGMENT_ROUTING_NODE)
+                                   || (prev_node == SR_TRAFFIC_ENG_NODE)
+                                   || (prev_node == SR_SEGMENT_LIST_NODE)
+                                   || (prev_node == SR_POLICY_NODE)
+                                   || (prev_node == SR_CANDIDATE_DYN_NODE)
+                                   || (prev_node == PCEP_NODE)
+                                   || (prev_node == PCEP_PCE_CONFIG_NODE)
+                                   || (prev_node == PCEP_PCE_NODE)
+                                   || (prev_node == PCEP_PCC_NODE))
+                                  && (tried > 0)) {
+                               ending = (vty->node != SEGMENT_ROUTING_NODE)
+                                        && (vty->node != SR_TRAFFIC_ENG_NODE)
+                                        && (vty->node != SR_SEGMENT_LIST_NODE)
+                                        && (vty->node != SR_POLICY_NODE)
+                                        && (vty->node != SR_CANDIDATE_DYN_NODE)
+                                        && (vty->node != PCEP_NODE)
+                                        && (vty->node != PCEP_PCE_CONFIG_NODE)
+                                        && (vty->node != PCEP_PCE_NODE)
+                                        && (vty->node != PCEP_PCC_NODE);
+                               if (ending)
+                                       tried--;
+                               while (tried-- > 0)
+                                       vty_out(vty, "exit\n");
+                               if (ending)
+                                       vty_out(vty, "end\n");
                        } else if (tried) {
                                vty_out(vty, "end\n");
                        }
@@ -1144,12 +1186,10 @@ static char *command_generator(const char *text, int state)
                cmd_free_strvec(vline);
        }
 
-       if (matched && matched[index])
-               /*
-                * this is free()'d by readline, but we leak 1 count of
-                * MTYPE_COMPLETION
-                */
+       if (matched && matched[index]) {
+               XCOUNTFREE(MTYPE_COMPLETION, matched[index]);
                return matched[index++];
+       }
 
        XFREE(MTYPE_TMP, matched);
 
@@ -1221,6 +1261,73 @@ static struct cmd_node pw_node = {
        .prompt = "%s(config-pw)# ",
 };
 
+#if defined(HAVE_PATHD)
+static struct cmd_node segment_routing_node = {
+       .name = "segment-routing",
+       .node = SEGMENT_ROUTING_NODE,
+       .parent_node = CONFIG_NODE,
+       .prompt = "%s(config-sr)# ",
+};
+
+static struct cmd_node sr_traffic_eng_node = {
+       .name = "sr traffic-eng",
+       .node = SR_TRAFFIC_ENG_NODE,
+       .parent_node = SEGMENT_ROUTING_NODE,
+       .prompt = "%s(config-sr-te)# ",
+};
+
+static struct cmd_node srte_segment_list_node = {
+       .name = "srte segment-list",
+       .node = SR_SEGMENT_LIST_NODE,
+       .parent_node = SR_TRAFFIC_ENG_NODE,
+       .prompt = "%s(config-sr-te-segment-list)# ",
+};
+
+static struct cmd_node srte_policy_node = {
+       .name = "srte policy",
+       .node = SR_POLICY_NODE,
+       .parent_node = SR_TRAFFIC_ENG_NODE,
+       .prompt = "%s(config-sr-te-policy)# ",
+};
+
+static struct cmd_node srte_candidate_dyn_node = {
+       .name = "srte candidate-dyn",
+       .node = SR_CANDIDATE_DYN_NODE,
+       .parent_node = SR_POLICY_NODE,
+       .prompt = "%s(config-sr-te-candidate)# ",
+};
+
+#if defined(HAVE_PATHD_PCEP)
+static struct cmd_node pcep_node = {
+       .name = "srte pcep",
+       .node = PCEP_NODE,
+       .parent_node = SR_TRAFFIC_ENG_NODE,
+       .prompt = "%s(config-sr-te-pcep)# "
+};
+
+static struct cmd_node pcep_pcc_node = {
+       .name = "srte pcep pcc",
+       .node = PCEP_PCC_NODE,
+       .parent_node = PCEP_NODE,
+       .prompt = "%s(config-sr-te-pcep-pcc)# ",
+};
+
+static struct cmd_node pcep_pce_node = {
+       .name = "srte pcep pce-peer",
+       .node = PCEP_PCE_NODE,
+       .parent_node = PCEP_NODE,
+       .prompt = "%s(config-sr-te-pcep-pce-peer)# ",
+};
+
+static struct cmd_node pcep_pce_config_node = {
+       .name = "srte pcep pce-config",
+       .node = PCEP_PCE_CONFIG_NODE,
+       .parent_node = PCEP_NODE,
+       .prompt = "%s(pcep-sr-te-pcep-pce-config)# ",
+};
+#endif /* HAVE_PATHD_PCEP */
+#endif /* HAVE_PATHD */
+
 static struct cmd_node vrf_node = {
        .name = "vrf",
        .node = VRF_NODE,
@@ -1720,11 +1827,16 @@ DEFUNSH(VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd,
 }
 
 #if defined(HAVE_CUMULUS)
+#if CONFDATE > 20211115
+CPP_NOTICE("Use of `address-family evpn` is deprecated please remove don't forget frr-reload.py")
+#endif
 DEFUNSH_HIDDEN(VTYSH_BGPD, address_family_evpn2, address_family_evpn2_cmd,
               "address-family evpn",
               "Enter Address Family command mode\n"
               "EVPN Address family\n")
 {
+       vty_out(vty,
+               "This command is deprecated please convert to `address-family l2vpn evpn`\n");
        vty->node = BGP_EVPN_NODE;
        return CMD_SUCCESS;
 }
@@ -1971,6 +2083,102 @@ DEFUNSH(VTYSH_FABRICD, router_openfabric, router_openfabric_cmd, "router openfab
 }
 #endif /* HAVE_FABRICD */
 
+#if defined(HAVE_PATHD)
+DEFUNSH(VTYSH_PATHD, segment_routing, segment_routing_cmd,
+       "segment-routing",
+       "Configure segment routing\n")
+{
+       vty->node = SEGMENT_ROUTING_NODE;
+       return CMD_SUCCESS;
+}
+
+DEFUNSH(VTYSH_PATHD, sr_traffic_eng, sr_traffic_eng_cmd,
+       "traffic-eng",
+       "Configure SR traffic engineering\n")
+{
+       vty->node = SR_TRAFFIC_ENG_NODE;
+       return CMD_SUCCESS;
+}
+
+DEFUNSH(VTYSH_PATHD, srte_segment_list, srte_segment_list_cmd,
+       "segment-list WORD$name",
+       "Segment List\n"
+       "Segment List Name\n")
+{
+       vty->node = SR_SEGMENT_LIST_NODE;
+       return CMD_SUCCESS;
+}
+
+DEFUNSH(VTYSH_PATHD, srte_policy, srte_policy_cmd,
+       "policy color (0-4294967295) endpoint <A.B.C.D|X:X::X:X>",
+       "Segment Routing Policy\n"
+       "SR Policy color\n"
+       "SR Policy color value\n"
+       "SR Policy endpoint\n"
+       "SR Policy endpoint IPv4 address\n"
+       "SR Policy endpoint IPv6 address\n")
+{
+       vty->node = SR_POLICY_NODE;
+       return CMD_SUCCESS;
+}
+
+DEFUNSH(VTYSH_PATHD, srte_policy_candidate_dyn_path,
+       srte_policy_candidate_dyn_path_cmd,
+       "candidate-path preference (0-4294967295) name WORD dynamic",
+       "Segment Routing Policy Candidate Path\n"
+       "Segment Routing Policy Candidate Path Preference\n"
+       "Administrative Preference\n"
+       "Segment Routing Policy Candidate Path Name\n"
+       "Symbolic Name\n"
+       "Dynamic Path\n")
+{
+       vty->node = SR_CANDIDATE_DYN_NODE;
+       return CMD_SUCCESS;
+}
+
+#if defined(HAVE_PATHD_PCEP)
+
+DEFUNSH(VTYSH_PATHD, pcep, pcep_cmd,
+       "pcep",
+       "Configure SR pcep\n")
+{
+       vty->node = PCEP_NODE;
+       return CMD_SUCCESS;
+}
+
+DEFUNSH(VTYSH_PATHD, pcep_cli_pcc, pcep_cli_pcc_cmd,
+       "[no] pcc",
+       NO_STR
+       "PCC configuration\n")
+{
+       vty->node = PCEP_PCC_NODE;
+       return CMD_SUCCESS;
+}
+
+DEFUNSH(VTYSH_PATHD, pcep_cli_pce, pcep_cli_pce_cmd,
+       "[no] pce WORD",
+       NO_STR
+       "PCE configuration\n"
+       "Peer name\n")
+{
+       vty->node = PCEP_PCE_NODE;
+       return CMD_SUCCESS;
+}
+
+DEFUNSH(VTYSH_PATHD, pcep_cli_pcep_pce_config, pcep_cli_pcep_pce_config_cmd,
+       "[no] pce-config WORD",
+       NO_STR
+       "PCEP peer Configuration Group\n"
+       "PCEP peer Configuration Group name\n")
+{
+       vty->node = PCEP_PCE_CONFIG_NODE;
+       return CMD_SUCCESS;
+}
+
+#endif /* HAVE_PATHD_PCEP */
+
+#endif /* HAVE_PATHD */
+
 DEFUNSH(VTYSH_RMAP, vtysh_route_map, vtysh_route_map_cmd,
        "route-map WORD <deny|permit> (1-65535)",
        "Create route-map or enter route-map command mode\n"
@@ -2095,7 +2303,7 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_exit_all, vtysh_exit_all_cmd, "exit",
        return vtysh_exit(vty);
 }
 
-DEFUNSH(VTYSH_ALL, vtysh_quit_all, vtysh_quit_all_cmd, "quit",
+DEFUNSH(VTYSH_REALLYALL, vtysh_quit_all, vtysh_quit_all_cmd, "quit",
        "Exit current mode and down to previous mode\n")
 {
        return vtysh_exit_all(self, vty, argc, argv);
@@ -2344,6 +2552,20 @@ DEFUNSH(VTYSH_KEYS, vtysh_quit_keys, vtysh_quit_keys_cmd, "quit",
        return vtysh_exit_keys(self, vty, argc, argv);
 }
 
+#if defined(HAVE_PATHD)
+DEFUNSH(VTYSH_PATHD, vtysh_exit_pathd, vtysh_exit_pathd_cmd, "exit",
+       "Exit current mode and down to previous mode\n")
+{
+       return vtysh_exit(vty);
+}
+
+DEFUNSH(VTYSH_PATHD, vtysh_quit_pathd, vtysh_quit_pathd_cmd, "quit",
+       "Exit current mode and down to previous mode\n")
+{
+       return vtysh_exit_pathd(self, vty, argc, argv);
+}
+#endif /* HAVE_PATHD */
+
 DEFUNSH(VTYSH_ALL, vtysh_exit_line_vty, vtysh_exit_line_vty_cmd, "exit",
        "Exit current mode and down to previous mode\n")
 {
@@ -2447,28 +2669,64 @@ DEFUNSH(VTYSH_INTERFACE, vtysh_quit_interface, vtysh_quit_interface_cmd, "quit",
        return vtysh_exit_interface(self, vty, argc, argv);
 }
 
-DEFUN (vtysh_show_poll,
-       vtysh_show_poll_cmd,
-       "show thread poll",
-       SHOW_STR
-       "Thread information\n"
-       "Thread Poll Information\n")
+static char *do_prepend(struct vty *vty, struct cmd_token **argv, int argc)
+{
+       const char *argstr[argc + 1];
+       int i, off = 0;
+
+       if (vty->node != VIEW_NODE) {
+               off = 1;
+               argstr[0] = "do";
+       }
+
+       for (i = 0; i < argc; i++)
+               argstr[i + off] = argv[i]->arg;
+
+       return frrstr_join(argstr, argc + off, " ");
+}
+
+static int show_per_daemon(struct vty *vty, struct cmd_token **argv, int argc,
+                          const char *headline)
 {
        unsigned int i;
        int ret = CMD_SUCCESS;
-       char line[100];
+       char *line = do_prepend(vty, argv, argc);
 
-       snprintf(line, sizeof(line), "do show thread poll\n");
        for (i = 0; i < array_size(vtysh_client); i++)
                if (vtysh_client[i].fd >= 0) {
-                       vty_out(vty, "Thread statistics for %s:\n",
-                               vtysh_client[i].name);
+                       vty_out(vty, headline, vtysh_client[i].name);
                        ret = vtysh_client_execute(&vtysh_client[i], line);
                        vty_out(vty, "\n");
                }
+
+       XFREE(MTYPE_TMP, line);
+
+       return ret;
+}
+
+static int show_one_daemon(struct vty *vty, struct cmd_token **argv, int argc,
+                          const char *name)
+{
+       int ret;
+       char *line = do_prepend(vty, argv, argc);
+
+       ret = vtysh_client_execute_name(name, line);
+
+       XFREE(MTYPE_TMP, line);
+
        return ret;
 }
 
+DEFUN (vtysh_show_poll,
+       vtysh_show_poll_cmd,
+       "show thread poll",
+       SHOW_STR
+       "Thread information\n"
+       "Thread Poll Information\n")
+{
+       return show_per_daemon(vty, argv, argc, "Thread statistics for %s:\n");
+}
+
 #ifndef EXCLUDE_CPU_TIME
 DEFUN (vtysh_show_thread,
        vtysh_show_thread_cmd,
@@ -2478,23 +2736,7 @@ DEFUN (vtysh_show_thread,
        "Thread CPU usage\n"
        "Display filter (rwtexb)\n")
 {
-       unsigned int i;
-       int idx = 0;
-       int ret = CMD_SUCCESS;
-       char line[100];
-
-       const char *filter =
-               argv_find(argv, argc, "FILTER", &idx) ? argv[idx]->arg : "";
-
-       snprintf(line, sizeof(line), "do show thread cpu %s\n", filter);
-       for (i = 0; i < array_size(vtysh_client); i++)
-               if (vtysh_client[i].fd >= 0) {
-                       vty_out(vty, "Thread statistics for %s:\n",
-                               vtysh_client[i].name);
-                       ret = vtysh_client_execute(&vtysh_client[i], line);
-                       vty_out(vty, "\n");
-               }
-       return ret;
+       return show_per_daemon(vty, argv, argc, "Thread statistics for %s:\n");
 }
 #endif
 
@@ -2504,19 +2746,8 @@ DEFUN (vtysh_show_work_queues,
        SHOW_STR
        "Work Queue information\n")
 {
-       unsigned int i;
-       int ret = CMD_SUCCESS;
-       char line[] = "do show work-queues\n";
-
-       for (i = 0; i < array_size(vtysh_client); i++)
-               if (vtysh_client[i].fd >= 0) {
-                       vty_out(vty, "Work queue statistics for %s:\n",
-                               vtysh_client[i].name);
-                       ret = vtysh_client_execute(&vtysh_client[i], line);
-                       vty_out(vty, "\n");
-               }
-
-       return ret;
+       return show_per_daemon(vty, argv, argc,
+                              "Work queue statistics for %s:\n");
 }
 
 DEFUN (vtysh_show_work_queues_daemon,
@@ -2526,10 +2757,7 @@ DEFUN (vtysh_show_work_queues_daemon,
        "Work Queue information\n"
        DAEMONS_STR)
 {
-       int idx_protocol = 2;
-
-       return vtysh_client_execute_name(argv[idx_protocol]->text,
-                                        "show work-queues\n");
+       return show_one_daemon(vty, argv, argc - 1, argv[argc - 1]->text);
 }
 
 DEFUNSH(VTYSH_ZEBRA, vtysh_link_params, vtysh_link_params_cmd, "link-params",
@@ -2547,21 +2775,6 @@ DEFUNSH(VTYSH_ZEBRA, exit_link_params, exit_link_params_cmd, "exit-link-params",
        return CMD_SUCCESS;
 }
 
-static int show_per_daemon(const char *line, const char *headline)
-{
-       unsigned int i;
-       int ret = CMD_SUCCESS;
-
-       for (i = 0; i < array_size(vtysh_client); i++)
-               if (vtysh_client[i].fd >= 0) {
-                       vty_out(vty, headline, vtysh_client[i].name);
-                       ret = vtysh_client_execute(&vtysh_client[i], line);
-                       vty_out(vty, "\n");
-               }
-
-       return ret;
-}
-
 DEFUNSH_HIDDEN (0x00,
                 vtysh_debug_all,
                 vtysh_debug_all_cmd,
@@ -2579,7 +2792,7 @@ DEFUN (vtysh_show_debugging,
        SHOW_STR
        DEBUG_STR)
 {
-       return show_per_daemon("do show debugging\n", "");
+       return show_per_daemon(vty, argv, argc, "");
 }
 
 DEFUN (vtysh_show_debugging_hashtable,
@@ -2590,6 +2803,8 @@ DEFUN (vtysh_show_debugging_hashtable,
        "Statistics about hash tables\n"
        "Statistics about hash tables\n")
 {
+       bool stats = strmatch(argv[argc - 1]->text, "statistics");
+
        vty_out(vty, "\n");
        vty_out(vty,
                "Load factor (LF) - average number of elements across all buckets\n");
@@ -2601,7 +2816,7 @@ DEFUN (vtysh_show_debugging_hashtable,
                "and indicates the typical deviation of bucket chain length\n");
        vty_out(vty, "from the value in the corresponding load factor.\n\n");
 
-       return show_per_daemon("do show debugging hashtable\n",
+       return show_per_daemon(vty, argv, stats ? argc - 1 : argc,
                               "Hashtable statistics for %s:\n");
 }
 
@@ -2621,12 +2836,7 @@ DEFUN (vtysh_show_error_code,
 
        /* If it's not a shared code, send it to all the daemons */
        if (arg < LIB_FERR_START || arg > LIB_FERR_END) {
-               char *fcmd = argv_concat(argv, argc, 0);
-               char cmd[256];
-
-               snprintf(cmd, sizeof(cmd), "do %s", fcmd);
-               show_per_daemon(cmd, "");
-               XFREE(MTYPE_TMP, fcmd);
+               show_per_daemon(vty, argv, argc, "");
                /* Otherwise, print it ourselves to avoid duplication */
        } else {
                bool json = strmatch(argv[argc - 1]->text, "json");
@@ -2659,11 +2869,7 @@ DEFUN (show_yang_operational_data,
        "YANG module translator\n"
        DAEMONS_STR)
 {
-       int idx_protocol = argc - 1;
-       char *fcmd = argv_concat(argv, argc - 1, 0);
-       int ret = vtysh_client_execute_name(argv[idx_protocol]->text, fcmd);
-       XFREE(MTYPE_TMP, fcmd);
-       return ret;
+       return show_one_daemon(vty, argv, argc - 1, argv[argc - 1]->text);
 }
 
 DEFUNSH(VTYSH_ALL, debug_nb,
@@ -2689,6 +2895,22 @@ DEFUNSH(VTYSH_ALL, debug_nb,
        return CMD_SUCCESS;
 }
 
+DEFUN (vtysh_show_history,
+       vtysh_show_history_cmd,
+       "show history",
+       SHOW_STR
+       "The list of commands stored in history\n")
+{
+       HIST_ENTRY **hlist = history_list();
+       int i = 0;
+
+       while (hlist[i]) {
+               vty_out(vty, "%s\n", hlist[i]->line);
+               i++;
+       }
+       return CMD_SUCCESS;
+}
+
 /* Memory */
 DEFUN (vtysh_show_memory,
        vtysh_show_memory_cmd,
@@ -2696,7 +2918,7 @@ DEFUN (vtysh_show_memory,
        SHOW_STR
        "Memory statistics\n")
 {
-       return show_per_daemon("do show memory\n", "Memory statistics for %s:\n");
+       return show_per_daemon(vty, argv, argc, "Memory statistics for %s:\n");
 }
 
 DEFUN (vtysh_show_modules,
@@ -2705,8 +2927,7 @@ DEFUN (vtysh_show_modules,
        SHOW_STR
        "Loaded modules\n")
 {
-       return show_per_daemon("do show modules\n",
-                              "Module information for %s:\n");
+       return show_per_daemon(vty, argv, argc, "Module information for %s:\n");
 }
 
 /* Logging commands. */
@@ -2716,7 +2937,7 @@ DEFUN (vtysh_show_logging,
        SHOW_STR
        "Show current logging configuration\n")
 {
-       return show_per_daemon("do show logging\n",
+       return show_per_daemon(vty, argv, argc,
                               "Logging configuration for %s:\n");
 }
 
@@ -3185,7 +3406,7 @@ DEFUN (vtysh_copy_to_running,
        int ret;
        const char *fname = argv[1]->arg;
 
-       ret = vtysh_read_config(fname);
+       ret = vtysh_read_config(fname, true);
 
        /* Return to enable mode - the 'read_config' api leaves us up a level */
        vtysh_execute_no_pager("enable");
@@ -4142,6 +4363,64 @@ void vtysh_init_vty(void)
        install_element(BFD_PROFILE_NODE, &vtysh_end_all_cmd);
 #endif /* HAVE_BFDD */
 
+#if defined(HAVE_PATHD)
+       install_node(&segment_routing_node);
+       install_node(&sr_traffic_eng_node);
+       install_node(&srte_segment_list_node);
+       install_node(&srte_policy_node);
+       install_node(&srte_candidate_dyn_node);
+
+       install_element(SEGMENT_ROUTING_NODE, &vtysh_exit_pathd_cmd);
+       install_element(SEGMENT_ROUTING_NODE, &vtysh_quit_pathd_cmd);
+       install_element(SR_TRAFFIC_ENG_NODE, &vtysh_exit_pathd_cmd);
+       install_element(SR_TRAFFIC_ENG_NODE, &vtysh_quit_pathd_cmd);
+       install_element(SR_SEGMENT_LIST_NODE, &vtysh_exit_pathd_cmd);
+       install_element(SR_SEGMENT_LIST_NODE, &vtysh_quit_pathd_cmd);
+       install_element(SR_POLICY_NODE, &vtysh_exit_pathd_cmd);
+       install_element(SR_POLICY_NODE, &vtysh_quit_pathd_cmd);
+       install_element(SR_CANDIDATE_DYN_NODE, &vtysh_exit_pathd_cmd);
+       install_element(SR_CANDIDATE_DYN_NODE, &vtysh_quit_pathd_cmd);
+
+       install_element(SEGMENT_ROUTING_NODE, &vtysh_end_all_cmd);
+       install_element(SR_TRAFFIC_ENG_NODE, &vtysh_end_all_cmd);
+       install_element(SR_SEGMENT_LIST_NODE, &vtysh_end_all_cmd);
+       install_element(SR_POLICY_NODE, &vtysh_end_all_cmd);
+       install_element(SR_CANDIDATE_DYN_NODE, &vtysh_end_all_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);
+       install_element(SR_TRAFFIC_ENG_NODE, &srte_policy_cmd);
+       install_element(SR_POLICY_NODE, &srte_policy_candidate_dyn_path_cmd);
+
+#if defined(HAVE_PATHD_PCEP)
+       install_node(&pcep_node);
+       install_node(&pcep_pcc_node);
+       install_node(&pcep_pce_node);
+       install_node(&pcep_pce_config_node);
+
+       install_element(PCEP_NODE, &vtysh_exit_pathd_cmd);
+       install_element(PCEP_NODE, &vtysh_quit_pathd_cmd);
+       install_element(PCEP_PCC_NODE, &vtysh_exit_pathd_cmd);
+       install_element(PCEP_PCC_NODE, &vtysh_quit_pathd_cmd);
+       install_element(PCEP_PCE_NODE, &vtysh_exit_pathd_cmd);
+       install_element(PCEP_PCE_NODE, &vtysh_quit_pathd_cmd);
+       install_element(PCEP_PCE_CONFIG_NODE, &vtysh_exit_pathd_cmd);
+       install_element(PCEP_PCE_CONFIG_NODE, &vtysh_quit_pathd_cmd);
+
+       install_element(PCEP_NODE, &vtysh_end_all_cmd);
+       install_element(PCEP_PCC_NODE, &vtysh_end_all_cmd);
+       install_element(PCEP_PCE_NODE, &vtysh_end_all_cmd);
+       install_element(PCEP_PCE_CONFIG_NODE, &vtysh_end_all_cmd);
+
+       install_element(SR_TRAFFIC_ENG_NODE, &pcep_cmd);
+       install_element(PCEP_NODE, &pcep_cli_pcc_cmd);
+       install_element(PCEP_NODE, &pcep_cli_pcep_pce_config_cmd);
+       install_element(PCEP_NODE, &pcep_cli_pce_cmd);
+#endif /* HAVE_PATHD_PCEP */
+
+#endif /* HAVE_PATHD */
+
        /* keychain */
        install_node(&keychain_node);
        install_element(CONFIG_NODE, &key_chain_cmd);
@@ -4194,7 +4473,7 @@ void vtysh_init_vty(void)
        install_element(VRF_NODE, &vtysh_end_all_cmd);
        install_element(VRF_NODE, &vtysh_exit_vrf_cmd);
        install_element(VRF_NODE, &vtysh_quit_vrf_cmd);
-       
+
        install_node(&rmap_node);
        install_element(CONFIG_NODE, &vtysh_route_map_cmd);
        install_element(RMAP_NODE, &vtysh_exit_rmap_cmd);
@@ -4279,11 +4558,12 @@ void vtysh_init_vty(void)
        install_element(CONFIG_NODE, &vtysh_debug_memstats_cmd);
 
        /* northbound */
-       install_element(VIEW_NODE, &show_yang_operational_data_cmd);
+       install_element(ENABLE_NODE, &show_yang_operational_data_cmd);
        install_element(ENABLE_NODE, &debug_nb_cmd);
        install_element(CONFIG_NODE, &debug_nb_cmd);
 
        /* misc lib show commands */
+       install_element(VIEW_NODE, &vtysh_show_history_cmd);
        install_element(VIEW_NODE, &vtysh_show_memory_cmd);
        install_element(VIEW_NODE, &vtysh_show_modules_cmd);
        install_element(VIEW_NODE, &vtysh_show_work_queues_cmd);
index d2675a81b9650120b419e72d0533b2e57109ac26..20e1e1b0e92618eba021dd9fe2056c3246763a69 100644 (file)
@@ -43,6 +43,7 @@ DECLARE_MGROUP(MVTYSH)
 #define VTYSH_BFDD      0x10000
 #define VTYSH_FABRICD   0x20000
 #define VTYSH_VRRPD     0x40000
+#define VTYSH_PATHD     0x80000
 
 #define VTYSH_WAS_ACTIVE (-2)
 
@@ -51,7 +52,7 @@ DECLARE_MGROUP(MVTYSH)
 /* watchfrr is not in ALL since library CLI functions should not be
  * run on it (logging & co. should stay in a fixed/frozen config, and
  * things like prefix lists are not even initialised) */
-#define VTYSH_ALL        VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD
+#define VTYSH_ALL        VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD|VTYSH_PATHD
 #define VTYSH_ACL         VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA
 #define VTYSH_RMAP       VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_FABRICD
 #define VTYSH_INTERFACE          VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD
@@ -92,7 +93,7 @@ void config_add_line(struct list *, const char *);
 
 int vtysh_mark_file(const char *filename);
 
-int vtysh_read_config(const char *);
+int vtysh_read_config(const char *filename, bool dry_run);
 int vtysh_write_config_integrated(void);
 
 void vtysh_config_parse_line(void *, const char *);
index 4b6c648d2fa46b9076e05856a3ac7b61dd24e823..47f426b5e0723c31903f1e1b1321e90ad9bf75c0 100644 (file)
@@ -485,8 +485,10 @@ void vtysh_config_dump(void)
                                 * are not under the VRF node.
                                 */
                                if (config->index == INTERFACE_NODE
-                                   && list_isempty(config->line))
+                                   && list_isempty(config->line)) {
+                                       config_del(config);
                                        continue;
+                               }
 
                                vty_out(vty, "%s\n", config->name);
 
@@ -513,7 +515,7 @@ void vtysh_config_dump(void)
 }
 
 /* Read up configuration file from file_name. */
-static int vtysh_read_file(FILE *confp)
+static int vtysh_read_file(FILE *confp, bool dry_run)
 {
        struct vty *vty;
        int ret;
@@ -526,9 +528,15 @@ static int vtysh_read_file(FILE *confp)
        vtysh_execute_no_pager("enable");
        vtysh_execute_no_pager("configure terminal");
 
+       if (!dry_run)
+               vtysh_execute_no_pager("XFRR_start_configuration");
+
        /* Execute configuration file. */
        ret = vtysh_config_from_file(vty, confp);
 
+       if (!dry_run)
+               vtysh_execute_no_pager("XFRR_end_configuration");
+
        vtysh_execute_no_pager("end");
        vtysh_execute_no_pager("disable");
 
@@ -538,7 +546,7 @@ static int vtysh_read_file(FILE *confp)
 }
 
 /* Read up configuration file from config_default_dir. */
-int vtysh_read_config(const char *config_default_dir)
+int vtysh_read_config(const char *config_default_dir, bool dry_run)
 {
        FILE *confp = NULL;
        int ret;
@@ -551,7 +559,7 @@ int vtysh_read_config(const char *config_default_dir)
                return CMD_ERR_NO_FILE;
        }
 
-       ret = vtysh_read_file(confp);
+       ret = vtysh_read_file(confp, dry_run);
        fclose(confp);
 
        return (ret);
index 1ca219a26c50eb4ebf29b8ecff90d4ec135b3cc2..db7cc312d684ed4d022cc5ef9e2180a460a347bd 100644 (file)
@@ -153,7 +153,8 @@ static void usage(int status)
                        progname);
        else
                printf("Usage : %s [OPTION...]\n\n"
-                      "Integrated shell for FRR. \n\n"
+                      "Integrated shell for FRR (version " FRR_VERSION "). \n"
+                      "Configured with:\n    " FRR_CONFIG_ARGS "\n\n"
                       "-b, --boot               Execute boot startup configuration\n"
                       "-c, --command            Execute argument as command\n"
                       "-d, --daemon             Connect only to the specified daemon\n"
@@ -458,7 +459,7 @@ int main(int argc, char **argv, char **env)
                /* Read vtysh configuration file before connecting to daemons.
                 * (file may not be readable to calling user in SUID mode) */
                suid_on();
-               vtysh_read_config(vtysh_config);
+               vtysh_read_config(vtysh_config, dryrun);
                suid_off();
        }
        /* Error code library system */
@@ -477,9 +478,9 @@ int main(int argc, char **argv, char **env)
        /* Start execution only if not in dry-run mode */
        if (dryrun && !cmd) {
                if (inputfile) {
-                       ret = vtysh_read_config(inputfile);
+                       ret = vtysh_read_config(inputfile, dryrun);
                } else {
-                       ret = vtysh_read_config(frr_config);
+                       ret = vtysh_read_config(frr_config, dryrun);
                }
 
                exit(ret);
@@ -560,7 +561,7 @@ int main(int argc, char **argv, char **env)
 
        if (inputfile) {
                vtysh_flock_config(inputfile);
-               ret = vtysh_read_config(inputfile);
+               ret = vtysh_read_config(inputfile, dryrun);
                vtysh_unflock_config();
                exit(ret);
        }
@@ -669,7 +670,7 @@ int main(int argc, char **argv, char **env)
        /* Boot startup configuration file. */
        if (boot_flag) {
                vtysh_flock_config(frr_config);
-               ret = vtysh_read_config(frr_config);
+               ret = vtysh_read_config(frr_config, dryrun);
                vtysh_unflock_config();
                if (ret) {
                        fprintf(stderr,
index cb1a6a8f568f9963c38bce7256a50c67d8e3c78f..1840e3728c9ea52f066661c0ae181c98d8fe060d 100644 (file)
@@ -358,6 +358,13 @@ submodule frr-bgp-common {
         "Apply administrative shutdown to newly configured peers.";
     }
 
+    leaf suppress-duplicates {
+      type boolean;
+      default "true";
+      description
+        "Suppress duplicate updates if the route actually not changed.";
+    }
+
     leaf ebgp-requires-policy {
       type boolean;
       default "true";
index 2fb5d13fa76952298a75f4aa283c0d6910fa137d..24998a470df85f9b8c2826533925f28473cf89ed 100644 (file)
@@ -598,6 +598,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast" {
@@ -626,6 +628,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast" {
@@ -654,7 +658,9 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
-  }
+
+    uses structure-neighbor-group-filter-config;
+   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast" {
     uses structure-neighbor-group-add-paths;
@@ -682,6 +688,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast" {
@@ -710,6 +718,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast" {
@@ -734,6 +744,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast" {
@@ -758,6 +770,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn" {
@@ -772,6 +786,8 @@ module frr-bgp {
     uses structure-neighbor-route-server;
 
     uses structure-neighbor-group-soft-reconfiguration;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec" {
@@ -780,6 +796,8 @@ module frr-bgp {
     uses structure-neighbor-route-server;
 
     uses structure-neighbor-group-soft-reconfiguration;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec" {
@@ -788,6 +806,8 @@ module frr-bgp {
     uses structure-neighbor-route-server;
 
     uses structure-neighbor-group-soft-reconfiguration;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast" {
@@ -855,6 +875,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast" {
@@ -883,6 +905,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast" {
@@ -911,6 +935,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast" {
@@ -939,6 +965,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast" {
@@ -1037,6 +1065,8 @@ module frr-bgp {
     uses structure-neighbor-route-server;
 
     uses structure-neighbor-group-soft-reconfiguration;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec" {
@@ -1045,6 +1075,8 @@ module frr-bgp {
     uses structure-neighbor-route-server;
 
     uses structure-neighbor-group-soft-reconfiguration;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast" {
@@ -1112,6 +1144,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast" {
@@ -1140,6 +1174,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast" {
@@ -1168,6 +1204,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast" {
@@ -1196,6 +1234,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast" {
@@ -1224,6 +1264,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast" {
@@ -1248,6 +1290,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast" {
@@ -1272,6 +1316,8 @@ module frr-bgp {
     uses structure-neighbor-group-soft-reconfiguration;
 
     uses structure-neighbor-weight;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn" {
@@ -1294,6 +1340,8 @@ module frr-bgp {
     uses structure-neighbor-route-server;
 
     uses structure-neighbor-group-soft-reconfiguration;
+
+    uses structure-neighbor-group-filter-config;
   }
 
   augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec" {
@@ -1302,5 +1350,7 @@ module frr-bgp {
     uses structure-neighbor-route-server;
 
     uses structure-neighbor-group-soft-reconfiguration;
+
+    uses structure-neighbor-group-filter-config;
   }
 }
index 400a09317895377f585b8d5a52689630bb2264a1..eb84dd746083d03f5eaf8cab71d3ae065e232f7f 100644 (file)
@@ -154,29 +154,33 @@ module frr-filter {
                 }
               }
               case cisco {
-                leaf host {
-                  description "Host to match";
-                  type inet:ipv4-address;
-                }
-                container network {
-                  leaf address {
-                    mandatory true;
-                    description "Network address part.";
+                choice standard-value {
+                  description "Source value to match";
+
+                  leaf host {
+                    description "Host to match";
                     type inet:ipv4-address;
                   }
-                  leaf mask {
-                    mandatory true;
-                    description "Network mask/wildcard part.";
-                    type inet:ipv4-address;
+                  container network {
+                    leaf address {
+                      mandatory true;
+                      description "Network address part.";
+                      type inet:ipv4-address;
+                    }
+                    leaf mask {
+                      mandatory true;
+                      description "Network mask/wildcard part.";
+                      type inet:ipv4-address;
+                    }
+                  }
+                  leaf source-any {
+                    /*
+                     * Was `any`, however it conflicts with `any` leaf
+                     * outside this choice.
+                     */
+                    description "Match any";
+                    type empty;
                   }
-                }
-                leaf source-any {
-                  /*
-                   * Was `any`, however it conflicts with `any` leaf
-                   * outside this choice.
-                   */
-                  description "Match any";
-                  type empty;
                 }
 
                 choice extended-value {
index b63d0f97ecbd697461f09ad901e7b8db835b5415..e2971dc5cfe0bdaa78fac2dd65fdf726e76a8caa 100644 (file)
@@ -71,14 +71,13 @@ module frr-igmp {
       type boolean;
       default "false";
       description
-        "Enable IGMP protocol on the interface.";
+        "Enable IGMP flag on the interface.";
     }
 
     leaf version {
       type uint8 {
         range "2..3";
       }
-      default "3";
       description
         "IGMP version.";
     }
@@ -156,8 +155,8 @@ module frr-igmp {
    */
   augment "/frr-interface:lib/frr-interface:interface" {
     container igmp {
-      description
-        "IGMP interface parameters.";
+      presence
+        "Configure IGMP on an interface.";
       uses interface-config-attributes;
       list address-family {
         key "address-family";
index c3b39e3750800e1ead3a60c75e6e47093187e1d0..812dd4159d7b49814b57f9f96900bac5e8feea5d 100644 (file)
@@ -244,6 +244,14 @@ module frr-isisd {
     }
   }
 
+  typedef access-list-ref {
+    type string;
+  }
+
+  typedef prefix-list-ref {
+    type string;
+  }
+
   grouping redistribute-attributes {
     description
       "Common optional attributes of any redistribute entry.";
@@ -336,6 +344,133 @@ module frr-isisd {
     }
   }
 
+  grouping global-config-lfa {
+    container lfa {
+      description
+        "LFA configuration.";
+
+      leaf load-sharing {
+        type boolean;
+        default "true";
+        description
+          "Load share prefixes across multiple backups.";
+      }
+      leaf priority-limit {
+        type enumeration {
+          enum "critical" {
+            value 0;
+            description
+              "Compute for critical priority prefixes only.";
+          }
+          enum "high" {
+            value 1;
+            description
+              "Compute for critical & high priority prefixes.";
+          }
+          enum "medium" {
+            value 2;
+            description
+              "Compute for critical, high & medium priority prefixes.";
+          }
+        }
+        description
+          "Limit backup computation up to the prefix priority.";
+      }
+      list tiebreaker {
+        key "index";
+        unique "type";
+        description
+          "Configure tiebreaker for multiple backups.";
+        leaf index {
+          type uint8 {
+            range "1..255";
+          }
+          description
+            "Preference order among tiebreakers.";
+        }
+        leaf type {
+          type enumeration {
+            enum "downstream" {
+              value 0;
+              description
+                "Prefer backup path via downstream node.";
+            }
+            enum "lowest-backup-metric" {
+              value 1;
+              description
+                "Prefer backup path with lowest total metric.";
+            }
+            enum "node-protecting" {
+              value 2;
+              description
+                "Prefer node protecting backup path.";
+            }
+          }
+          mandatory true;
+          description
+            "Tiebreaker type.";
+        }
+      }
+    }
+  }
+
+  grouping global-config-remote-lfa {
+    container remote-lfa {
+      description
+        "Remote LFA configuration.";
+
+      leaf prefix-list {
+        type prefix-list-ref;
+        description
+          "Filter PQ node router ID based on prefix list.";
+      }
+    }
+  }
+
+  grouping interface-config-lfa {
+    container lfa {
+      description
+        "LFA configuration.";
+      leaf enable {
+        type boolean;
+        default false;
+        description
+          "Enables LFA computation.";
+      }
+      leaf-list exclude-interface {
+        type frr-interface:interface-ref;
+        description
+          "Exclude an interface from computation.";
+      }
+    }
+  }
+
+  grouping interface-config-remote-lfa {
+    container remote-lfa {
+      description
+        "Remote LFA configuration.";
+
+      leaf enable {
+        type boolean;
+        default false;
+        description
+          "Enables remote LFA computation using LDP tunnels.";
+        must ". = 'false' or ../../lfa/enable = 'true'" {
+          error-message
+            "Remote LFA depends on classic LFA being configured in the interface.";
+        }
+
+      }
+      leaf maximum-metric {
+        type uint32 {
+          range "1..16777215";
+        }
+        description
+          "Limit remote LFA node selection within the metric.";
+      }
+    }
+  }
+
   grouping interface-config-ti-lfa {
     container ti-lfa {
       description
@@ -664,11 +799,23 @@ module frr-isisd {
       container level-1 {
         description
           "Level-1 IP Fast-reroute configuration.";
+        must "./lfa/enable = 'false' or ./ti-lfa/enable = 'false'" {
+          error-message
+            "Can't enable both classic LFA and TI-LFA in the same interface.";
+        }
+        uses interface-config-lfa;
+        uses interface-config-remote-lfa;
         uses interface-config-ti-lfa;
       }
       container level-2 {
         description
           "Level-2 IP Fast-reroute configuration.";
+        must "./lfa/enable = 'false' or ./ti-lfa/enable = 'false'" {
+          error-message
+            "Can't enable both classic LFA and TI-LFA in the same interface.";
+        }
+        uses interface-config-lfa;
+        uses interface-config-remote-lfa;
         uses interface-config-ti-lfa;
       }
     }
@@ -1095,6 +1242,42 @@ module frr-isisd {
               "Minimum time between consecutive level-2 SPFs.";
           }
         }
+
+        container prefix-priorities {
+          description
+            "SPF Prefix Priority configuration";
+
+          container critical {
+            description
+              "Critical prefix priority";
+            leaf access-list-name {
+              type access-list-ref;
+              description
+                "Access List to determine prefixes for
+                 this priority";
+            }
+          }
+          container high {
+            description
+              "High prefix priority";
+            leaf access-list-name {
+              type access-list-ref;
+              description
+                "Access List to determine prefixes for
+                 this priority";
+            }
+          }
+          container medium {
+            description
+              "Medium prefix priority";
+            leaf access-list-name {
+              type access-list-ref;
+              description
+                "Access List to determine prefixes for
+                 this priority";
+            }
+          }
+        }
       }
 
       container area-password {
@@ -1249,6 +1432,23 @@ module frr-isisd {
         }
       }
 
+      container fast-reroute {
+        description
+          "IP Fast-reroute configuration.";
+        container level-1 {
+          description
+            "Level-1 IP Fast-reroute configuration.";
+          uses global-config-lfa;
+          uses global-config-remote-lfa;
+        }
+        container level-2 {
+          description
+            "Level-2 IP Fast-reroute configuration.";
+          uses global-config-lfa;
+          uses global-config-remote-lfa;
+        }
+      }
+
       leaf log-adjacency-changes {
         type boolean;
         default "false";
index 619514de7d4b2e50a8981f4c006fa7160dd20345..2df2e2958e92499b2be4af5c59ff5e855e53e993 100644 (file)
@@ -61,7 +61,7 @@ module frr-nexthop {
     type union {
       type inet:ip-address;
       type string {
-        pattern '';
+        pattern "";
       }
     }
   }
@@ -160,6 +160,7 @@ module frr-nexthop {
       description
         "The nexthop vrf name, if different from the route.";
     }
+
     leaf gateway {
       type frr-nexthop:optional-ip-address;
       description
@@ -173,15 +174,12 @@ module frr-nexthop {
     }
 
     leaf bh-type {
-      when "../nh-type = 'blackhole'";
       type blackhole-type;
       description
         "A blackhole sub-type, if the nexthop is a blackhole type.";
     }
 
     leaf onlink {
-      when "../nh-type = 'ip4-ifindex' or
-            ../nh-type = 'ip6-ifindex'";
       type boolean;
       default "false";
       description
diff --git a/yang/frr-pathd.yang b/yang/frr-pathd.yang
new file mode 100644 (file)
index 0000000..03f0d3b
--- /dev/null
@@ -0,0 +1,480 @@
+module frr-pathd {
+  yang-version 1.1;
+  namespace "http://frrouting.org/yang/pathd";
+  prefix frr-pathd;
+
+  import ietf-inet-types {
+    prefix inet;
+  }
+  import ietf-yang-types {
+    prefix yang;
+  }
+  import ietf-routing-types {
+    prefix rt-types;
+  }
+  import frr-interface {
+    prefix frr-interface;
+  }
+
+  organization
+    "Free Range Routing";
+  contact
+    "FRR Users List:       <mailto:frog@lists.frrouting.org>
+     FRR Development List: <mailto:dev@lists.frrouting.org>";
+  description
+    "This module defines a model for managing FRR pathd daemon.";
+
+  revision 2018-11-06 {
+    description
+      "Initial revision.";
+  }
+
+  typedef protocol-origin-type {
+    description
+      "Indication for the protocol origin of an object.";
+    type enumeration {
+      enum pcep {
+        value 1;
+        description "The object was created through PCEP";
+      }
+      enum bgp {
+        value 2;
+        description "The object was created through GBP";
+      }
+      enum local {
+        value 3;
+        description "The object was created through CLI, Yang model via Netconf, gRPC, etc";
+      }
+    }
+  }
+
+  typedef originator-type {
+        type string {
+          length "1..64";
+        }
+        description
+          "Identifier of the originator of an object, could be 'config', '1.1.1.1:4189' or '2001:db8:85a3::8a2e:370:7334:4189'";
+      }
+
+  container pathd {
+    container srte {
+      list segment-list {
+        key "name";
+        description "Segment-list properties";
+        leaf name {
+          type string {
+            length "1..64";
+          }
+          description "Segment-list name";
+        }
+        leaf protocol-origin {
+          type protocol-origin-type;
+          mandatory true;
+          description
+            "Indication for the protocol origin of the segment list.";
+        }
+        leaf originator {
+          type originator-type;
+          mandatory true;
+          description "Originator of the segment list";
+        }
+        list segment {
+          key "index";
+          description "Configure Segment/hop at the index";
+          leaf index {
+            type uint32;
+            description "Segment index";
+          }
+          leaf sid-value {
+            type rt-types:mpls-label;
+            mandatory true;
+            description "MPLS label value";
+          }
+          container nai {
+            presence "The segement has a Node or Adjacency Identifier";
+            leaf type {
+              description "NAI type";
+              mandatory true;
+              type enumeration {
+                enum ipv4_node {
+                  value 1;
+                  description "IPv4 node identifier";
+                }
+                enum ipv6_node {
+                  value 2;
+                  description "IPv6 node identifier";
+                }
+                enum ipv4_adjacency {
+                  value 3;
+                  description "IPv4 adjacency";
+                }
+                enum ipv6_adjacency {
+                  value 4;
+                  description "IPv6 adjacency";
+                }
+                enum ipv4_unnumbered_adjacency {
+                  value 5;
+                  description "IPv4 unnumbered adjacency";
+                }
+              }
+            }
+            leaf local-address {
+              type inet:ip-address;
+              mandatory true;
+            }
+            leaf local-interface {
+              type uint32;
+              mandatory true;
+              when "../type = 'ipv4_unnumbered_adjacency'";
+            }
+            leaf remote-address {
+              type inet:ip-address;
+              mandatory true;
+              when "../type = 'ipv4_adjacency' or ../type = 'ipv6_adjacency' or ../type = 'ipv4_unnumbered_adjacency'";
+            }
+            leaf remote-interface {
+              type uint32;
+              mandatory true;
+              when "../type = 'ipv4_unnumbered_adjacency'";
+            }
+          }
+        }
+      }
+      list policy {
+        key "color endpoint";
+        unique "name";
+        leaf color {
+          type uint32;
+          description
+            "Color of the SR Policy.";
+        }
+        leaf endpoint {
+          type inet:ip-address;
+          description
+            "Indication for the endpoint of the SR Policy.";
+        }
+        leaf name {
+          type string {
+            length "1..64";
+          }
+          description
+            "Name of the SR Policy.";
+        }
+        leaf binding-sid {
+          type rt-types:mpls-label;
+          description
+            "BSID of the SR Policy.";
+        }
+        leaf is-operational {
+          type boolean;
+          config false;
+          description
+            "True if a valid candidate path of this policy is operational in zebra, False otherwise";
+        }
+        list candidate-path {
+          unique "name";
+          description
+            "List of Candidate Paths of the SR Policy.";
+          key "preference";
+          leaf preference {
+            type uint32;
+            description
+              "Administrative preference.";
+          }
+          leaf name {
+            type string {
+              length "1..64";
+            }
+            mandatory true;
+            description
+              "Symbolic Name of the Candidate Path.";
+          }
+          leaf is-best-candidate-path {
+            type boolean;
+            config false;
+            description
+              "True if the candidate path is the best candidate path, False otherwise";
+          }
+          leaf protocol-origin {
+            type protocol-origin-type;
+            mandatory true;
+            description
+              "Indication for the protocol origin of the Candidate Path.";
+          }
+          leaf originator {
+            type originator-type;
+            mandatory true;
+            description "Originator of the candidate path";
+          }
+          leaf discriminator {
+            type uint32;
+            config false;
+            description "Candidate path distinguisher";
+          }
+          leaf type {
+            description
+              "Type of the Candidate Path.";
+            mandatory true;
+            type enumeration {
+              enum explicit {
+                value 1;
+              }
+              enum dynamic {
+                value 2;
+              }
+            }
+          }
+          leaf segment-list-name {
+            type leafref {
+              path ../../../segment-list/name;
+            }
+            description
+              "The name of the Segment List to use as LSP.";
+          }
+          container constraints {
+            when "../type = 'dynamic'";
+            description
+              "Generic dynamic path constraints";
+            container bandwidth {
+              presence "If the candidate has a bandwidth constraint";
+              description
+                "The bandwidth needed by the candidate path.";
+              leaf required {
+                type boolean;
+                default "true";
+                description
+                  "If the bandwidth limitation is a requirement or only a suggestion";
+              }
+              leaf value {
+                mandatory true;
+                type decimal64 {
+                    fraction-digits 6;
+                }
+              }
+            }
+            container affinity {
+              description
+                "Affinity let you configure how the links should be used when calculating a path.";
+              leaf exclude-any {
+                type uint32;
+                description
+                  "A 32-bit vector representing a set of attribute filters which renders a link unacceptable.";
+              }
+              leaf include-any {
+                type uint32;
+                description
+                  "A 32-bit vector representing a set of attribute filters which renders a link acceptable. A null set (all bits set to zero) automatically passes.";
+              }
+              leaf include-all {
+                type uint32;
+                description
+                  "A 32-bit vector representing a set of attribute filters which must be present for a link to be acceptable.  A null set (all bits set to zero) automatically passes.";
+              }
+            }
+            list metrics {
+              key "type";
+              leaf type {
+                description
+                  "Type of the metric.";
+                type enumeration {
+                  enum igp {
+                    value 1;
+                    description "IGP metric";
+                  }
+                  enum te {
+                    value 2;
+                    description "TE metric";
+                  }
+                  enum hc {
+                    value 3;
+                    description "Hop Counts";
+                  }
+                  enum abc {
+                    value 4;
+                    description "Aggregate bandwidth consumption";
+                  }
+                  enum lmll {
+                    value 5;
+                    description "Load of the most loaded link";
+                  }
+                  enum cigp {
+                    value 6;
+                    description "Cumulative IGP cost";
+                  }
+                  enum cte {
+                    value 7;
+                    description "Cumulative TE cost";
+                  }
+                  enum pigp {
+                    value 8;
+                    description "P2MP IGP metric";
+                  }
+                  enum pte {
+                    value 9;
+                    description "P2MP TE metric";
+                  }
+                  enum phc {
+                    value 10;
+                    description "P2MP hop count metric";
+                  }
+                  enum msd {
+                    value 11;
+                    description "Segment-ID (SID) Depth";
+                  }
+                  enum pd {
+                    value 12;
+                    description "Path Delay metric";
+                  }
+                  enum pdv {
+                    value 13;
+                    description "Path Delay Variation metric";
+                  }
+                  enum pl {
+                    value 14;
+                    description "Path Loss metric";
+                  }
+                  enum ppd {
+                    value 15;
+                    description "P2MP Path Delay metric";
+                  }
+                  enum ppdv {
+                    value 16;
+                    description "P2MP Path Delay variation metric";
+                  }
+                  enum ppl {
+                    value 17;
+                    description "P2MP Path Loss metric";
+                  }
+                  enum nap {
+                    value 18;
+                    description "Number of adaptations on a path";
+                  }
+                  enum nlp {
+                    value 19;
+                    description "Number of layers on a path";
+                  }
+                  enum dc {
+                    value 20;
+                    description "Domain Count metric";
+                  }
+                  enum bnc {
+                    value 21;
+                    description "Border Node Count metric";
+                  }
+                }
+              }
+              leaf required {
+                type boolean;
+                default "true";
+                description
+                  "If the metric is a requirement, or if it is only a suggestion";
+              }
+              leaf is-bound {
+                type boolean;
+                description
+                  "Defines if the value is a bound (a maximum) for the path metric that must not be exceeded.";
+              }
+              leaf is-computed {
+                type boolean;
+                description
+                  "Defines if the value has been generated by the originator of the path.";
+              }
+              leaf value {
+                mandatory true;
+                type decimal64 {
+                    fraction-digits 6;
+                }
+              }
+            }
+            container objective-function {
+              presence "If the candidate has an objective function constraint";
+              description
+                "Define objective function constraint as a list of prefered functions";
+              leaf required {
+                type boolean;
+                default "true";
+                description
+                  "If an objective function is a requirement, or if it is only a suggestion";
+              }
+              leaf type {
+                description
+                  "Type of objective function.";
+                mandatory true;
+                type enumeration {
+                  enum mcp {
+                    value 1;
+                    description "Minimum Cost Path";
+                  }
+                  enum mlp {
+                    value 2;
+                    description "Minimum Load Path";
+                  }
+                  enum mbp {
+                    value 3;
+                    description "Maximum residual Bandwidth Path";
+                  }
+                  enum mbc {
+                    value 4;
+                    description "Minimize aggregate Bandwidth Consumption";
+                  }
+                  enum mll {
+                    value 5;
+                    description "Minimize the Load of the most loaded Link";
+                  }
+                  enum mcc {
+                    value 6;
+                    description "Minimize the Cumulative Cost of a set of paths";
+                  }
+                  enum spt {
+                    value 7;
+                    description "Shortest Path Tree";
+                  }
+                  enum mct {
+                    value 8;
+                    description "Minimum Cost Tree";
+                  }
+                  enum mplp {
+                    value 9;
+                    description "Minimum Packet Loss Path";
+                  }
+                  enum mup {
+                    value 10;
+                    description "Maximum Under-Utilized Path";
+                  }
+                  enum mrup {
+                    value 11;
+                    description "Maximum Reserved Under-Utilized Path";
+                  }
+                  enum mtd {
+                    value 12;
+                    description "Minimize the number of Transit Domains";
+                  }
+                  enum mbn {
+                    value 13;
+                    description "Minimize the number of Border Nodes";
+                  }
+                  enum mctd {
+                    value 14;
+                    description "Minimize the number of Common Transit Domains";
+                  }
+                  enum msl {
+                    value 15;
+                    description "Minimize the number of Shared Links";
+                  }
+                  enum mss {
+                    value 16;
+                    description "Minimize the number of Shared SRLGs";
+                  }
+                  enum msn {
+                    value 17;
+                    description "Minimize the number of Shared Nodes";
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
index 2135d22f67b0c47b185ab62676babd21d6943984..f959ff8be5c859e8bf61c624352cdd523b42e9a2 100644 (file)
@@ -82,26 +82,19 @@ module frr-pim {
       "A grouping defining pim global attributes.";
 
     leaf ecmp {
-      type empty;
+      type boolean;
+      default "false";
       description
         "Enable PIM ECMP.";
     }
 
     leaf ecmp-rebalance {
-      type empty;
+      type boolean;
+      default "false";
       description
         "Enable PIM ECMP Rebalance.";
     }
 
-    leaf join-prune-interval {
-      type uint16 {
-        range "60..600";
-      }
-      default "60";
-      description
-        "Join Prune Send Interval in seconds.";
-    }
-
     leaf keep-alive-timer {
       type uint16 {
         range "31..60000";
@@ -119,26 +112,7 @@ module frr-pim {
       description
         "RP keep alive Timer in seconds.";
     }
-
-    leaf packets {
-      type uint8 {
-        range "1..100";
-      }
-      default "3";
-      description
-        "Number of packets to process at one time per fd.";
-    }
-
-    leaf register-suppress-time {
-      type uint16 {
-        range "5..60000";
-      }
-      default "60";
-      description
-        "Register Suppress Timer.";
-    }
   }
-
   grouping per-af-global-pim-config-attributes {
     description
       "A grouping defining per address family pim global attributes";
@@ -148,7 +122,8 @@ module frr-pim {
         description
           "Only applicable to IPv4 address family.";
       }
-      type empty;
+      type boolean;
+      default "true";
       description
         "Send v6 secondary addresses.";
     }
@@ -241,7 +216,7 @@ module frr-pim {
     }
 
     container mlag {
-      description
+      presence
         "Multi-chassis link aggregation.";
 
      leaf peerlink-rif {
@@ -300,22 +275,14 @@ module frr-pim {
       "A grouping defining pim interface attributes.";
 
     leaf pim-enable {
-      type empty;
+      type boolean;
+      default "false";
       description
         "Enable PIM flag on the interface.";
     }
 
-    leaf dr-priority {
-      type uint32 {
-        range "1..4294967295";
-      }
-      default 1;
-      description
-        "DR (Designated Router) priority";
-    }
-
     leaf hello-interval {
-      type uint16 {
+      type uint8 {
         range "1..180";
       }
       default "30";
@@ -324,7 +291,7 @@ module frr-pim {
     }
 
     leaf hello-holdtime {
-      type uint16 {
+      type uint8 {
         range "1..180";
       }
       description
@@ -364,22 +331,34 @@ module frr-pim {
     }
 
     leaf bsm {
-      type empty;
+      type boolean;
+      default "false";
       description
         "Enables BSM support on the interface.";
     }
 
     leaf unicast-bsm {
-      type empty;
+      type boolean;
+      default "false";
       description
         "Accept/Send unicast BSM on the interface.";
     }
 
     leaf active-active {
-      type empty;
+      type boolean;
+      default "false";
       description
         "Mark interface as Active-Active for MLAG operations.";
     }
+
+    leaf dr-priority {
+      type uint32 {
+        range "1..4294967295";
+      }
+      default 1;
+      description
+        "DR (Designated Router) priority";
+    }
   } // interface-pim-config-attributes
 
   grouping per-af-interface-pim-config-attributes {
@@ -455,8 +434,8 @@ module frr-pim {
    */
   augment "/frr-interface:lib/frr-interface:interface" {
     container pim {
-      description
-        "PIM interface parameters.";
+      presence
+        "Configure PIM on an interface.";
       uses interface-pim-config-attributes;
       list address-family {
         key "address-family";
@@ -467,5 +446,33 @@ module frr-pim {
       }
     }
   }
-}
 
+  container pim {
+    description
+      "PIM router parameters.";
+    leaf packets {
+      type uint8 {
+        range "1..100";
+      }
+      default "3";
+      description
+        "Number of packets to process at one time per fd.";
+    }
+    leaf join-prune-interval {
+      type uint16 {
+        range "60..600";
+      }
+      default "60";
+      description
+        "Join Prune Send Interval in seconds.";
+    }
+    leaf register-suppress-time {
+      type uint16 {
+        range "5..60000";
+      }
+      default "60";
+      description
+        "Register Suppress Timer.";
+    }
+  }
+}
index 281b4903c072a8474f524d60f740d5ea0656430a..98ff3a83c65b7bfa9714dc40ee94a678faa0dc70 100644 (file)
@@ -63,7 +63,13 @@ module frr-staticd {
 
   grouping staticd-prefix-attributes {
     list path-list {
-      key "distance";
+      key "table-id distance";
+      leaf table-id {
+        type uint32;
+        description
+          "Table-id";
+      }
+
       leaf distance {
         type frr-rt:administrative-distance;
         description
@@ -77,13 +83,6 @@ module frr-staticd {
           "Route tag";
       }
 
-      leaf table-id {
-        type uint32;
-        default "0";
-        description
-          "Table-id";
-      }
-
       uses frr-nexthop:frr-nexthop;
     }
   }
index c99d6d987790ffecfa18a364f30d5aff9506982b..200eaeb0b542faf1dae75055542c4c2fc091834c 100644 (file)
@@ -246,7 +246,7 @@ module frr-vrrpd {
           }
 
           uses ip-vrrp-state {
-            augment "./counter/tx" {
+            augment "counter/tx" {
               leaf gratuitous-arp {
                 type yang:zero-based-counter32;
                 description
@@ -266,7 +266,7 @@ module frr-vrrpd {
           }
 
           uses ip-vrrp-state {
-            augment "./counter/tx" {
+            augment "counter/tx" {
               leaf neighbor-advertisement {
                 type yang:zero-based-counter32;
                 description
index 5be93dc4e9967664b1d08187af40a9c3b4d24697..47fc5089012efe2dc075dadf2821941bc603cd42 100644 (file)
@@ -82,3 +82,7 @@ dist_yangmodels_DATA += yang/frr-bgp-bmp.yang
 dist_yangmodels_DATA += yang/frr-bgp-types.yang
 dist_yangmodels_DATA += yang/frr-bgp.yang
 endif
+
+if PATHD
+dist_yangmodels_DATA += yang/frr-pathd.yang
+endif
index 70ea2e38050d01dba382cb55dcc5a53d4053c44a..c885c533e6439151436fb21682755f46783111dc 100644 (file)
@@ -402,10 +402,10 @@ void connected_down(struct interface *ifp, struct connected *ifc)
         * head.
         */
        rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
-                  0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false, true);
+                  0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false);
 
        rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
-                  0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false, true);
+                  0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false);
 
        /* Schedule LSP forwarding entries for processing, if appropriate. */
        if (zvrf->vrf->vrf_id == VRF_DEFAULT) {
diff --git a/zebra/debug_nl.c b/zebra/debug_nl.c
new file mode 100644 (file)
index 0000000..842579f
--- /dev/null
@@ -0,0 +1,1246 @@
+/*
+ * Copyright (c) 2018 Rafael Zalamena
+ *
+ * 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 THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+#include <zebra.h>
+
+#if defined(HAVE_NETLINK) && defined(NETLINK_DEBUG)
+
+#include <sys/socket.h>
+
+#include <linux/netlink.h>
+#include <linux/nexthop.h>
+#include <linux/rtnetlink.h>
+#include <net/if_arp.h>
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include "zebra/rt_netlink.h"
+
+const char *nlmsg_type2str(uint16_t type)
+{
+       switch (type) {
+       /* Generic */
+       case NLMSG_NOOP:
+               return "NOOP";
+       case NLMSG_ERROR:
+               return "ERROR";
+       case NLMSG_DONE:
+               return "DONE";
+       case NLMSG_OVERRUN:
+               return "OVERRUN";
+
+       /* RTM */
+       case RTM_NEWLINK:
+               return "NEWLINK";
+       case RTM_DELLINK:
+               return "DELLINK";
+       case RTM_GETLINK:
+               return "GETLINK";
+       case RTM_SETLINK:
+               return "SETLINK";
+
+       case RTM_NEWADDR:
+               return "NEWADDR";
+       case RTM_DELADDR:
+               return "DELADDR";
+       case RTM_GETADDR:
+               return "GETADDR";
+
+       case RTM_NEWROUTE:
+               return "NEWROUTE";
+       case RTM_DELROUTE:
+               return "DELROUTE";
+       case RTM_GETROUTE:
+               return "GETROUTE";
+
+       case RTM_NEWNEIGH:
+               return "NEWNEIGH";
+       case RTM_DELNEIGH:
+               return "DELNEIGH";
+       case RTM_GETNEIGH:
+               return "GETNEIGH";
+
+       case RTM_NEWRULE:
+               return "NEWRULE";
+       case RTM_DELRULE:
+               return "DELRULE";
+       case RTM_GETRULE:
+               return "GETRULE";
+
+       case RTM_NEWNEXTHOP:
+               return "NEWNEXTHOP";
+       case RTM_DELNEXTHOP:
+               return "DELNEXTHOP";
+       case RTM_GETNEXTHOP:
+               return "GETNEXTHOP";
+
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *af_type2str(int type)
+{
+       switch (type) {
+       case AF_UNSPEC:
+               return "AF_UNSPEC";
+       case AF_UNIX:
+               return "AF_UNIX";
+       case AF_INET:
+               return "AF_INET";
+       case AF_INET6:
+               return "AF_INET6";
+       case AF_BRIDGE:
+               return "AF_BRIDGE";
+       case AF_NETLINK:
+               return "AF_NETLINK";
+#ifdef AF_MPLS
+       case AF_MPLS:
+               return "AF_MPLS";
+#endif /* AF_MPLS */
+       case AF_BLUETOOTH:
+               return "AF_BLUETOOTH";
+       case AF_VSOCK:
+               return "AF_VSOCK";
+       case AF_KEY:
+               return "AF_KEY";
+       case AF_PACKET:
+               return "AF_PACKET";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *ifi_type2str(int type)
+{
+       switch (type) {
+       case ARPHRD_ETHER:
+               return "ETHER";
+       case ARPHRD_EETHER:
+               return "EETHER";
+       case ARPHRD_NETROM:
+               return "NETROM";
+       case ARPHRD_AX25:
+               return "AX25";
+       case ARPHRD_PRONET:
+               return "PRONET";
+       case ARPHRD_CHAOS:
+               return "CHAOS";
+       case ARPHRD_IEEE802:
+               return "IEEE802";
+       case ARPHRD_ARCNET:
+               return "ARCNET";
+       case ARPHRD_APPLETLK:
+               return "APPLETLK";
+       case ARPHRD_DLCI:
+               return "DLCI";
+       case ARPHRD_ATM:
+               return "ATM";
+       case ARPHRD_METRICOM:
+               return "METRICOM";
+       case ARPHRD_IEEE1394:
+               return "IEEE1394";
+       case ARPHRD_EUI64:
+               return "EUI64";
+       case ARPHRD_INFINIBAND:
+               return "INFINIBAND";
+       case ARPHRD_SLIP:
+               return "SLIP";
+       case ARPHRD_CSLIP:
+               return "CSLIP";
+       case ARPHRD_SLIP6:
+               return "SLIP6";
+       case ARPHRD_CSLIP6:
+               return "CSLIP6";
+       case ARPHRD_RSRVD:
+               return "RSRVD";
+       case ARPHRD_ADAPT:
+               return "ADAPT";
+       case ARPHRD_ROSE:
+               return "ROSE";
+       case ARPHRD_X25:
+               return "X25";
+       case ARPHRD_PPP:
+               return "PPP";
+       case ARPHRD_HDLC:
+               return "HDLC";
+       case ARPHRD_LAPB:
+               return "LAPB";
+       case ARPHRD_DDCMP:
+               return "DDCMP";
+       case ARPHRD_RAWHDLC:
+               return "RAWHDLC";
+       case ARPHRD_TUNNEL:
+               return "TUNNEL";
+       case ARPHRD_TUNNEL6:
+               return "TUNNEL6";
+       case ARPHRD_FRAD:
+               return "FRAD";
+       case ARPHRD_SKIP:
+               return "SKIP";
+       case ARPHRD_LOOPBACK:
+               return "LOOPBACK";
+       case ARPHRD_LOCALTLK:
+               return "LOCALTLK";
+       case ARPHRD_FDDI:
+               return "FDDI";
+       case ARPHRD_BIF:
+               return "BIF";
+       case ARPHRD_SIT:
+               return "SIT";
+       case ARPHRD_IPDDP:
+               return "IPDDP";
+       case ARPHRD_IPGRE:
+               return "IPGRE";
+       case ARPHRD_PIMREG:
+               return "PIMREG";
+       case ARPHRD_HIPPI:
+               return "HIPPI";
+       case ARPHRD_ASH:
+               return "ASH";
+       case ARPHRD_ECONET:
+               return "ECONET";
+       case ARPHRD_IRDA:
+               return "IRDA";
+       case ARPHRD_FCPP:
+               return "FCPP";
+       case ARPHRD_FCAL:
+               return "FCAL";
+       case ARPHRD_FCPL:
+               return "FCPL";
+       case ARPHRD_FCFABRIC:
+               return "FCFABRIC";
+       case ARPHRD_IEEE802_TR:
+               return "IEEE802_TR";
+       case ARPHRD_IEEE80211:
+               return "IEEE80211";
+       case ARPHRD_IEEE80211_PRISM:
+               return "IEEE80211_PRISM";
+       case ARPHRD_IEEE80211_RADIOTAP:
+               return "IEEE80211_RADIOTAP";
+       case ARPHRD_IEEE802154:
+               return "IEEE802154";
+#ifdef ARPHRD_VSOCKMON
+       case ARPHRD_VSOCKMON:
+               return "VSOCKMON";
+#endif /* ARPHRD_VSOCKMON */
+       case ARPHRD_VOID:
+               return "VOID";
+       case ARPHRD_NONE:
+               return "NONE";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *rta_type2str(int type)
+{
+       switch (type) {
+       case IFLA_UNSPEC:
+               return "UNSPEC";
+       case IFLA_ADDRESS:
+               return "ADDRESS";
+       case IFLA_BROADCAST:
+               return "BROADCAST";
+       case IFLA_IFNAME:
+               return "IFNAME";
+       case IFLA_MTU:
+               return "MTU";
+       case IFLA_LINK:
+               return "LINK";
+       case IFLA_QDISC:
+               return "QDISC";
+       case IFLA_STATS:
+               return "STATS";
+       case IFLA_COST:
+               return "COST";
+       case IFLA_PRIORITY:
+               return "PRIORITY";
+       case IFLA_MASTER:
+               return "MASTER";
+       case IFLA_WIRELESS:
+               return "WIRELESS";
+       case IFLA_PROTINFO:
+               return "PROTINFO";
+       case IFLA_TXQLEN:
+               return "TXQLEN";
+       case IFLA_MAP:
+               return "MAP";
+       case IFLA_WEIGHT:
+               return "WEIGHT";
+       case IFLA_OPERSTATE:
+               return "OPERSTATE";
+       case IFLA_LINKMODE:
+               return "LINKMODE";
+       case IFLA_LINKINFO:
+               return "LINKINFO";
+       case IFLA_NET_NS_PID:
+               return "NET_NS_PID";
+       case IFLA_IFALIAS:
+               return "IFALIAS";
+       case IFLA_NUM_VF:
+               return "NUM_VF";
+       case IFLA_VFINFO_LIST:
+               return "VFINFO_LIST";
+       case IFLA_STATS64:
+               return "STATS64";
+       case IFLA_VF_PORTS:
+               return "VF_PORTS";
+       case IFLA_PORT_SELF:
+               return "PORT_SELF";
+       case IFLA_AF_SPEC:
+               return "AF_SPEC";
+       case IFLA_GROUP:
+               return "GROUP";
+       case IFLA_NET_NS_FD:
+               return "NET_NS_FD";
+       case IFLA_EXT_MASK:
+               return "EXT_MASK";
+       case IFLA_PROMISCUITY:
+               return "PROMISCUITY";
+       case IFLA_NUM_TX_QUEUES:
+               return "NUM_TX_QUEUES";
+       case IFLA_NUM_RX_QUEUES:
+               return "NUM_RX_QUEUES";
+       case IFLA_CARRIER:
+               return "CARRIER";
+       case IFLA_PHYS_PORT_ID:
+               return "PHYS_PORT_ID";
+       case IFLA_CARRIER_CHANGES:
+               return "CARRIER_CHANGES";
+       case IFLA_PHYS_SWITCH_ID:
+               return "PHYS_SWITCH_ID";
+       case IFLA_LINK_NETNSID:
+               return "LINK_NETNSID";
+       case IFLA_PHYS_PORT_NAME:
+               return "PHYS_PORT_NAME";
+       case IFLA_PROTO_DOWN:
+               return "PROTO_DOWN";
+#ifdef IFLA_GSO_MAX_SEGS
+       case IFLA_GSO_MAX_SEGS:
+               return "GSO_MAX_SEGS";
+#endif /* IFLA_GSO_MAX_SEGS */
+#ifdef IFLA_GSO_MAX_SIZE
+       case IFLA_GSO_MAX_SIZE:
+               return "GSO_MAX_SIZE";
+#endif /* IFLA_GSO_MAX_SIZE */
+#ifdef IFLA_PAD
+       case IFLA_PAD:
+               return "PAD";
+#endif /* IFLA_PAD */
+#ifdef IFLA_XDP
+       case IFLA_XDP:
+               return "XDP";
+#endif /* IFLA_XDP */
+#ifdef IFLA_EVENT
+       case IFLA_EVENT:
+               return "EVENT";
+#endif /* IFLA_EVENT */
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *rtm_type2str(int type)
+{
+       switch (type) {
+       case RTN_UNSPEC:
+               return "UNSPEC";
+       case RTN_UNICAST:
+               return "UNICAST";
+       case RTN_LOCAL:
+               return "LOCAL";
+       case RTN_BROADCAST:
+               return "BROADCAST";
+       case RTN_ANYCAST:
+               return "ANYCAST";
+       case RTN_MULTICAST:
+               return "MULTICAST";
+       case RTN_BLACKHOLE:
+               return "BLACKHOLE";
+       case RTN_UNREACHABLE:
+               return "UNREACHABLE";
+       case RTN_PROHIBIT:
+               return "PROHIBIT";
+       case RTN_THROW:
+               return "THROW";
+       case RTN_NAT:
+               return "NAT";
+       case RTN_XRESOLVE:
+               return "XRESOLVE";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *rtm_protocol2str(int type)
+{
+       switch (type) {
+       case RTPROT_UNSPEC:
+               return "UNSPEC";
+       case RTPROT_REDIRECT:
+               return "REDIRECT";
+       case RTPROT_KERNEL:
+               return "KERNEL";
+       case RTPROT_BOOT:
+               return "BOOT";
+       case RTPROT_STATIC:
+               return "STATIC";
+       case RTPROT_GATED:
+               return "GATED";
+       case RTPROT_RA:
+               return "RA";
+       case RTPROT_MRT:
+               return "MRT";
+       case RTPROT_ZEBRA:
+               return "ZEBRA";
+       case RTPROT_BIRD:
+               return "BIRD";
+       case RTPROT_DNROUTED:
+               return "DNROUTED";
+       case RTPROT_XORP:
+               return "XORP";
+       case RTPROT_NTK:
+               return "NTK";
+       case RTPROT_DHCP:
+               return "DHCP";
+       case RTPROT_MROUTED:
+               return "MROUTED";
+       case RTPROT_BABEL:
+               return "BABEL";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *rtm_scope2str(int type)
+{
+       switch (type) {
+       case RT_SCOPE_UNIVERSE:
+               return "UNIVERSE";
+       case RT_SCOPE_SITE:
+               return "SITE";
+       case RT_SCOPE_LINK:
+               return "LINK";
+       case RT_SCOPE_HOST:
+               return "HOST";
+       case RT_SCOPE_NOWHERE:
+               return "NOWHERE";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *rtm_rta2str(int type)
+{
+       switch (type) {
+       case RTA_UNSPEC:
+               return "UNSPEC";
+       case RTA_DST:
+               return "DST";
+       case RTA_SRC:
+               return "SRC";
+       case RTA_IIF:
+               return "IIF";
+       case RTA_OIF:
+               return "OIF";
+       case RTA_GATEWAY:
+               return "GATEWAY";
+       case RTA_PRIORITY:
+               return "PRIORITY";
+       case RTA_PREF:
+               return "PREF";
+       case RTA_PREFSRC:
+               return "PREFSRC";
+       case RTA_MARK:
+               return "MARK";
+       case RTA_METRICS:
+               return "METRICS";
+       case RTA_MULTIPATH:
+               return "MULTIPATH";
+       case RTA_PROTOINFO:
+               return "PROTOINFO";
+       case RTA_FLOW:
+               return "FLOW";
+       case RTA_CACHEINFO:
+               return "CACHEINFO";
+       case RTA_TABLE:
+               return "TABLE";
+       case RTA_MFC_STATS:
+               return "MFC_STATS";
+       case RTA_NH_ID:
+               return "NH_ID";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *neigh_rta2str(int type)
+{
+       switch (type) {
+       case NDA_UNSPEC:
+               return "UNSPEC";
+       case NDA_DST:
+               return "DST";
+       case NDA_LLADDR:
+               return "LLADDR";
+       case NDA_CACHEINFO:
+               return "CACHEINFO";
+       case NDA_PROBES:
+               return "PROBES";
+       case NDA_VLAN:
+               return "VLAN";
+       case NDA_PORT:
+               return "PORT";
+       case NDA_VNI:
+               return "VNI";
+       case NDA_IFINDEX:
+               return "IFINDEX";
+       case NDA_MASTER:
+               return "MASTER";
+       case NDA_LINK_NETNSID:
+               return "LINK_NETNSID";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *ifa_rta2str(int type)
+{
+       switch (type) {
+       case IFA_UNSPEC:
+               return "UNSPEC";
+       case IFA_ADDRESS:
+               return "ADDRESS";
+       case IFA_LOCAL:
+               return "LOCAL";
+       case IFA_LABEL:
+               return "LABEL";
+       case IFA_BROADCAST:
+               return "BROADCAST";
+       case IFA_ANYCAST:
+               return "ANYCAST";
+       case IFA_CACHEINFO:
+               return "CACHEINFO";
+       case IFA_MULTICAST:
+               return "MULTICAST";
+       case IFA_FLAGS:
+               return "FLAGS";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+const char *nhm_rta2str(int type)
+{
+       switch (type) {
+       case NHA_UNSPEC:
+               return "UNSPEC";
+       case NHA_ID:
+               return "ID";
+       case NHA_GROUP:
+               return "GROUP";
+       case NHA_GROUP_TYPE:
+               return "GROUP_TYPE";
+       case NHA_BLACKHOLE:
+               return "BLACKHOLE";
+       case NHA_OIF:
+               return "OIF";
+       case NHA_GATEWAY:
+               return "GATEWAY";
+       case NHA_ENCAP_TYPE:
+               return "ENCAP_TYPE";
+       case NHA_ENCAP:
+               return "ENCAP";
+       case NHA_GROUPS:
+               return "GROUPS";
+       case NHA_MASTER:
+               return "MASTER";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+static inline void flag_write(int flags, int flag, const char *flagstr,
+                             char *buf, size_t buflen)
+{
+       if (CHECK_FLAG(flags, flag) == 0)
+               return;
+
+       if (buf[0])
+               strlcat(buf, ",", buflen);
+
+       strlcat(buf, flagstr, buflen);
+}
+
+const char *nlmsg_flags2str(uint16_t flags, char *buf, size_t buflen)
+{
+       const char *bufp = buf;
+
+       *buf = 0;
+       /* Specific flags. */
+       flag_write(flags, NLM_F_REQUEST, "REQUEST", buf, buflen);
+       flag_write(flags, NLM_F_MULTI, "MULTI", buf, buflen);
+       flag_write(flags, NLM_F_ACK, "ACK", buf, buflen);
+       flag_write(flags, NLM_F_ECHO, "ECHO", buf, buflen);
+       flag_write(flags, NLM_F_DUMP, "DUMP", buf, buflen);
+
+       /* Netlink family type dependent. */
+       flag_write(flags, 0x0100, "(ROOT|REPLACE|CAPPED)", buf, buflen);
+       flag_write(flags, 0x0200, "(MATCH|EXCLUDE|ACK_TLVS)", buf, buflen);
+       flag_write(flags, 0x0400, "(ATOMIC|CREATE)", buf, buflen);
+       flag_write(flags, 0x0800, "(DUMP|APPEND)", buf, buflen);
+
+       return (bufp);
+}
+
+const char *if_flags2str(uint32_t flags, char *buf, size_t buflen)
+{
+       const char *bufp = buf;
+
+       *buf = 0;
+       flag_write(flags, IFF_UP, "UP", buf, buflen);
+       flag_write(flags, IFF_BROADCAST, "BROADCAST", buf, buflen);
+       flag_write(flags, IFF_DEBUG, "DEBUG", buf, buflen);
+       flag_write(flags, IFF_LOOPBACK, "LOOPBACK", buf, buflen);
+       flag_write(flags, IFF_POINTOPOINT, "POINTOPOINT", buf, buflen);
+       flag_write(flags, IFF_NOTRAILERS, "NOTRAILERS", buf, buflen);
+       flag_write(flags, IFF_RUNNING, "RUNNING", buf, buflen);
+       flag_write(flags, IFF_NOARP, "NOARP", buf, buflen);
+       flag_write(flags, IFF_PROMISC, "PROMISC", buf, buflen);
+       flag_write(flags, IFF_ALLMULTI, "ALLMULTI", buf, buflen);
+       flag_write(flags, IFF_MASTER, "MASTER", buf, buflen);
+       flag_write(flags, IFF_SLAVE, "SLAVE", buf, buflen);
+       flag_write(flags, IFF_MULTICAST, "MULTICAST", buf, buflen);
+       flag_write(flags, IFF_PORTSEL, "PORTSEL", buf, buflen);
+       flag_write(flags, IFF_AUTOMEDIA, "AUTOMEDIA", buf, buflen);
+       flag_write(flags, IFF_DYNAMIC, "DYNAMIC", buf, buflen);
+
+       return (bufp);
+}
+
+const char *rtm_flags2str(uint32_t flags, char *buf, size_t buflen)
+{
+       const char *bufp = buf;
+
+       *buf = 0;
+       flag_write(flags, RTM_F_NOTIFY, "NOTIFY", buf, buflen);
+       flag_write(flags, RTM_F_CLONED, "CLONED", buf, buflen);
+       flag_write(flags, RTM_F_EQUALIZE, "EQUALIZE", buf, buflen);
+
+       return (bufp);
+}
+
+const char *neigh_state2str(uint32_t flags, char *buf, size_t buflen)
+{
+       const char *bufp = buf;
+
+       *buf = 0;
+       flag_write(flags, NUD_INCOMPLETE, "INCOMPLETE", buf, buflen);
+       flag_write(flags, NUD_REACHABLE, "REACHABLE", buf, buflen);
+       flag_write(flags, NUD_STALE, "STALE", buf, buflen);
+       flag_write(flags, NUD_DELAY, "DELAY", buf, buflen);
+       flag_write(flags, NUD_PROBE, "PROBE", buf, buflen);
+       flag_write(flags, NUD_FAILED, "FAILED", buf, buflen);
+       flag_write(flags, NUD_NOARP, "NOARP", buf, buflen);
+       flag_write(flags, NUD_PERMANENT, "PERMANENT", buf, buflen);
+
+       return (bufp);
+}
+
+const char *neigh_flags2str(uint32_t flags, char *buf, size_t buflen)
+{
+       const char *bufp = buf;
+
+       *buf = 0;
+       flag_write(flags, NTF_USE, "USE", buf, buflen);
+       flag_write(flags, NTF_SELF, "SELF", buf, buflen);
+       flag_write(flags, NTF_MASTER, "MASTER", buf, buflen);
+       flag_write(flags, NTF_PROXY, "PROXY", buf, buflen);
+       flag_write(flags, NTF_EXT_LEARNED, "EXT_LEARNED", buf, buflen);
+#ifdef NTF_OFFLOADED
+       flag_write(flags, NTF_OFFLOADED, "OFFLOADED", buf, buflen);
+#endif /* NTF_OFFLOADED */
+       flag_write(flags, NTF_ROUTER, "ROUTER", buf, buflen);
+
+       return (bufp);
+}
+
+const char *ifa_flags2str(uint32_t flags, char *buf, size_t buflen)
+{
+       const char *bufp = buf;
+
+       *buf = 0;
+       flag_write(flags, IFA_F_SECONDARY, "SECONDARY", buf, buflen);
+       flag_write(flags, IFA_F_NODAD, "NODAD", buf, buflen);
+       flag_write(flags, IFA_F_OPTIMISTIC, "OPTIMISTIC", buf, buflen);
+       flag_write(flags, IFA_F_DADFAILED, "DADFAILED", buf, buflen);
+       flag_write(flags, IFA_F_HOMEADDRESS, "HOMEADDRESS", buf, buflen);
+       flag_write(flags, IFA_F_DEPRECATED, "DEPRECATED", buf, buflen);
+       flag_write(flags, IFA_F_TENTATIVE, "TENTATIVE", buf, buflen);
+       flag_write(flags, IFA_F_PERMANENT, "PERMANENT", buf, buflen);
+       flag_write(flags, IFA_F_MANAGETEMPADDR, "MANAGETEMPADDR", buf, buflen);
+       flag_write(flags, IFA_F_NOPREFIXROUTE, "NOPREFIXROUTE", buf, buflen);
+       flag_write(flags, IFA_F_MCAUTOJOIN, "MCAUTOJOIN", buf, buflen);
+       flag_write(flags, IFA_F_STABLE_PRIVACY, "STABLE_PRIVACY", buf, buflen);
+
+       return (bufp);
+}
+
+const char *nh_flags2str(uint32_t flags, char *buf, size_t buflen)
+{
+       const char *bufp = buf;
+
+       *buf = 0;
+       flag_write(flags, RTNH_F_DEAD, "DEAD", buf, buflen);
+       flag_write(flags, RTNH_F_PERVASIVE, "PERVASIVE", buf, buflen);
+       flag_write(flags, RTNH_F_ONLINK, "ONLINK", buf, buflen);
+       flag_write(flags, RTNH_F_OFFLOAD, "OFFLOAD", buf, buflen);
+       flag_write(flags, RTNH_F_LINKDOWN, "LINKDOWN", buf, buflen);
+       flag_write(flags, RTNH_F_UNRESOLVED, "UNRESOLVED", buf, buflen);
+
+       return (bufp);
+}
+
+/*
+ * Netlink abstractions.
+ */
+static void nllink_linkinfo_dump(struct rtattr *rta, size_t msglen)
+{
+       size_t plen;
+       char dbuf[128];
+
+next_rta:
+       /* Check the header for valid length and for outbound access. */
+       if (RTA_OK(rta, msglen) == 0)
+               return;
+
+       plen = RTA_PAYLOAD(rta);
+       zlog_debug("      linkinfo [len=%d (payload=%zu) type=(%d) %s]",
+                  rta->rta_len, plen, rta->rta_type,
+                  rta_type2str(rta->rta_type));
+       switch (rta->rta_type) {
+       case IFLA_INFO_KIND:
+               if (plen == 0) {
+                       zlog_debug("        invalid length");
+                       break;
+               }
+
+               snprintf(dbuf, sizeof(dbuf), "%s", (char *)RTA_DATA(rta));
+               zlog_debug("        %s", dbuf);
+               break;
+       case IFLA_INFO_SLAVE_KIND:
+               if (plen == 0) {
+                       zlog_debug("        invalid length");
+                       break;
+               }
+
+               snprintf(dbuf, sizeof(dbuf), "%s", (char *)RTA_DATA(rta));
+               zlog_debug("        %s", dbuf);
+               break;
+
+       default:
+               /* NOTHING: unhandled. */
+               break;
+       }
+
+       /* Get next pointer and start iteration again. */
+       rta = RTA_NEXT(rta, msglen);
+       goto next_rta;
+}
+
+static void nllink_dump(struct ifinfomsg *ifi, size_t msglen)
+{
+       uint8_t *datap;
+       struct rtattr *rta;
+       size_t plen, it;
+       uint32_t u32v;
+       char bytestr[16];
+       char dbuf[128];
+
+       /* Get the first attribute and go from there. */
+       rta = IFLA_RTA(ifi);
+next_rta:
+       /* Check the header for valid length and for outbound access. */
+       if (RTA_OK(rta, msglen) == 0)
+               return;
+
+       plen = RTA_PAYLOAD(rta);
+       zlog_debug("    rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
+                  plen, rta->rta_type, rta_type2str(rta->rta_type));
+       switch (rta->rta_type) {
+       case IFLA_IFNAME:
+       case IFLA_IFALIAS:
+               if (plen == 0) {
+                       zlog_debug("      invalid length");
+                       break;
+               }
+
+               snprintf(dbuf, sizeof(dbuf), "%s", (char *)RTA_DATA(rta));
+               zlog_debug("      %s", dbuf);
+               break;
+
+       case IFLA_MTU:
+       case IFLA_TXQLEN:
+       case IFLA_NUM_TX_QUEUES:
+       case IFLA_NUM_RX_QUEUES:
+       case IFLA_GROUP:
+       case IFLA_PROMISCUITY:
+#ifdef IFLA_GSO_MAX_SEGS
+       case IFLA_GSO_MAX_SEGS:
+#endif /* IFLA_GSO_MAX_SEGS */
+#ifdef IFLA_GSO_MAX_SIZE
+       case IFLA_GSO_MAX_SIZE:
+#endif /* IFLA_GSO_MAX_SIZE */
+       case IFLA_CARRIER_CHANGES:
+       case IFLA_MASTER:
+               if (plen < sizeof(uint32_t)) {
+                       zlog_debug("      invalid length");
+                       break;
+               }
+
+               u32v = *(uint32_t *)RTA_DATA(rta);
+               zlog_debug("      %u", u32v);
+               break;
+
+       case IFLA_ADDRESS:
+               datap = RTA_DATA(rta);
+               dbuf[0] = 0;
+               for (it = 0; it < plen; it++) {
+                       snprintf(bytestr, sizeof(bytestr), "%02X:", *datap);
+                       strlcat(dbuf, bytestr, sizeof(dbuf));
+                       datap++;
+               }
+               /* Remove trailing ':'. */
+               if (dbuf[0])
+                       dbuf[strlen(dbuf) - 1] = 0;
+
+               zlog_debug("      %s", dbuf[0] ? dbuf : "<empty>");
+               break;
+
+       case IFLA_LINKINFO:
+               nllink_linkinfo_dump(RTA_DATA(rta), msglen);
+               break;
+
+       default:
+               /* NOTHING: unhandled. */
+               break;
+       }
+
+       /* Get next pointer and start iteration again. */
+       rta = RTA_NEXT(rta, msglen);
+       goto next_rta;
+}
+
+static void nlroute_dump(struct rtmsg *rtm, size_t msglen)
+{
+       struct rtattr *rta;
+       size_t plen;
+       uint32_t u32v;
+
+       /* Get the first attribute and go from there. */
+       rta = RTM_RTA(rtm);
+next_rta:
+       /* Check the header for valid length and for outbound access. */
+       if (RTA_OK(rta, msglen) == 0)
+               return;
+
+       plen = RTA_PAYLOAD(rta);
+       zlog_debug("    rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
+                  plen, rta->rta_type, rtm_rta2str(rta->rta_type));
+       switch (rta->rta_type) {
+       case RTA_IIF:
+       case RTA_OIF:
+       case RTA_PRIORITY:
+       case RTA_TABLE:
+       case RTA_NH_ID:
+               u32v = *(uint32_t *)RTA_DATA(rta);
+               zlog_debug("      %u", u32v);
+               break;
+
+       case RTA_GATEWAY:
+       case RTA_DST:
+       case RTA_SRC:
+       case RTA_PREFSRC:
+               switch (plen) {
+               case sizeof(struct in_addr):
+                       zlog_debug("      %pI4",
+                                  (struct in_addr *)RTA_DATA(rta));
+                       break;
+               case sizeof(struct in6_addr):
+                       zlog_debug("      %pI6",
+                                  (struct in6_addr *)RTA_DATA(rta));
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       default:
+               /* NOTHING: unhandled. */
+               break;
+       }
+
+       /* Get next pointer and start iteration again. */
+       rta = RTA_NEXT(rta, msglen);
+       goto next_rta;
+}
+
+static void nlneigh_dump(struct ndmsg *ndm, size_t msglen)
+{
+       struct rtattr *rta;
+       uint8_t *datap;
+       size_t plen, it;
+       uint16_t vid;
+       char bytestr[16];
+       char dbuf[128];
+
+#ifndef NDA_RTA
+#define NDA_RTA(ndm)                                                           \
+       /* struct ndmsg *ndm; */                                               \
+       ((struct rtattr *)(((uint8_t *)(ndm))                                  \
+                          + NLMSG_ALIGN(sizeof(struct ndmsg))))
+#endif /* NDA_RTA */
+
+       /* Get the first attribute and go from there. */
+       rta = NDA_RTA(ndm);
+next_rta:
+       /* Check the header for valid length and for outbound access. */
+       if (RTA_OK(rta, msglen) == 0)
+               return;
+
+       plen = RTA_PAYLOAD(rta);
+       zlog_debug("    rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
+                  plen, rta->rta_type, neigh_rta2str(rta->rta_type));
+       switch (rta->rta_type) {
+       case NDA_LLADDR:
+               datap = RTA_DATA(rta);
+               dbuf[0] = 0;
+               for (it = 0; it < plen; it++) {
+                       snprintf(bytestr, sizeof(bytestr), "%02X:", *datap);
+                       strlcat(dbuf, bytestr, sizeof(dbuf));
+                       datap++;
+               }
+               /* Remove trailing ':'. */
+               if (dbuf[0])
+                       dbuf[strlen(dbuf) - 1] = 0;
+
+               zlog_debug("      %s", dbuf[0] ? dbuf : "<empty>");
+               break;
+
+       case NDA_DST:
+               switch (plen) {
+               case sizeof(struct in_addr):
+                       zlog_debug("      %pI4",
+                                  (struct in_addr *)RTA_DATA(rta));
+                       break;
+               case sizeof(struct in6_addr):
+                       zlog_debug("      %pI6",
+                                  (struct in6_addr *)RTA_DATA(rta));
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case NDA_VLAN:
+               vid = *(uint16_t *)RTA_DATA(rta);
+               zlog_debug("      %d", vid);
+               break;
+
+       default:
+               /* NOTHING: unhandled. */
+               break;
+       }
+
+       /* Get next pointer and start iteration again. */
+       rta = RTA_NEXT(rta, msglen);
+       goto next_rta;
+}
+
+static void nlifa_dump(struct ifaddrmsg *ifa, size_t msglen)
+{
+       struct rtattr *rta;
+       size_t plen;
+       uint32_t u32v;
+
+       /* Get the first attribute and go from there. */
+       rta = IFA_RTA(ifa);
+next_rta:
+       /* Check the header for valid length and for outbound access. */
+       if (RTA_OK(rta, msglen) == 0)
+               return;
+
+       plen = RTA_PAYLOAD(rta);
+       zlog_debug("    rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
+                  plen, rta->rta_type, ifa_rta2str(rta->rta_type));
+       switch (rta->rta_type) {
+       case IFA_UNSPEC:
+               u32v = *(uint32_t *)RTA_DATA(rta);
+               zlog_debug("      %u", u32v);
+               break;
+
+       case IFA_LABEL:
+               zlog_debug("      %s", (const char *)RTA_DATA(rta));
+               break;
+
+       case IFA_ADDRESS:
+       case IFA_LOCAL:
+       case IFA_BROADCAST:
+               switch (plen) {
+               case 4:
+                       zlog_debug("      %pI4",
+                                  (struct in_addr *)RTA_DATA(rta));
+                       break;
+               case 16:
+                       zlog_debug("      %pI6",
+                                  (struct in6_addr *)RTA_DATA(rta));
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       default:
+               /* NOTHING: unhandled. */
+               break;
+       }
+
+       /* Get next pointer and start iteration again. */
+       rta = RTA_NEXT(rta, msglen);
+       goto next_rta;
+}
+
+static void nlnh_dump(struct nhmsg *nhm, size_t msglen)
+{
+       struct rtattr *rta;
+       int ifindex;
+       size_t plen;
+       uint16_t u16v;
+       uint32_t u32v;
+       unsigned long count, i;
+       struct nexthop_grp *nhgrp;
+
+       rta = RTM_NHA(nhm);
+next_rta:
+       /* Check the header for valid length and for outbound access. */
+       if (RTA_OK(rta, msglen) == 0)
+               return;
+
+       plen = RTA_PAYLOAD(rta);
+       zlog_debug("    rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
+                  plen, rta->rta_type, nhm_rta2str(rta->rta_type));
+       switch (rta->rta_type) {
+       case NHA_ID:
+               u32v = *(uint32_t *)RTA_DATA(rta);
+               zlog_debug("      %u", u32v);
+               break;
+       case NHA_GROUP:
+               nhgrp = (struct nexthop_grp *)RTA_DATA(rta);
+               count = (RTA_PAYLOAD(rta) / sizeof(*nhgrp));
+               if (count == 0
+                   || (count * sizeof(*nhgrp)) != RTA_PAYLOAD(rta)) {
+                       zlog_debug("      invalid nexthop group received");
+                       return;
+               }
+
+               for (i = 0; i < count; i++)
+                       zlog_debug("      id %d weight %d", nhgrp[i].id,
+                                  nhgrp[i].weight);
+               break;
+       case NHA_ENCAP_TYPE:
+       case NHA_GROUP_TYPE:
+               u16v = *(uint16_t *)RTA_DATA(rta);
+               zlog_debug("      %d", u16v);
+               break;
+       case NHA_BLACKHOLE:
+               /* NOTHING */
+               break;
+       case NHA_OIF:
+               ifindex = *(int *)RTA_DATA(rta);
+               zlog_debug("      %d", ifindex);
+               break;
+       case NHA_GATEWAY:
+               switch (nhm->nh_family) {
+               case AF_INET:
+                       zlog_debug("      %pI4",
+                                  (struct in_addr *)RTA_DATA(rta));
+                       break;
+               case AF_INET6:
+                       zlog_debug("      %pI6",
+                                  (struct in6_addr *)RTA_DATA(rta));
+                       break;
+
+               default:
+                       zlog_debug("      invalid family %d", nhm->nh_family);
+                       break;
+               }
+               break;
+       case NHA_ENCAP:
+               /* TODO: handle MPLS labels. */
+               zlog_debug("      unparsed MPLS labels");
+               break;
+       case NHA_GROUPS:
+               /* TODO: handle this message. */
+               zlog_debug("      unparsed GROUPS message");
+               break;
+
+       default:
+               /* NOTHING: unhandled. */
+               break;
+       }
+
+       /* Get next pointer and start iteration again. */
+       rta = RTA_NEXT(rta, msglen);
+       goto next_rta;
+}
+
+void nl_dump(void *msg, size_t msglen)
+{
+       struct nlmsghdr *nlmsg = msg;
+       struct nlmsgerr *nlmsgerr;
+       struct rtgenmsg *rtgen;
+       struct ifaddrmsg *ifa;
+       struct ndmsg *ndm;
+       struct rtmsg *rtm;
+       struct nhmsg *nhm;
+       struct ifinfomsg *ifi;
+       char fbuf[128];
+       char ibuf[128];
+
+next_header:
+       zlog_debug(
+               "nlmsghdr [len=%u type=(%d) %s flags=(0x%04x) {%s} seq=%u pid=%u]",
+               nlmsg->nlmsg_len, nlmsg->nlmsg_type,
+               nlmsg_type2str(nlmsg->nlmsg_type), nlmsg->nlmsg_flags,
+               nlmsg_flags2str(nlmsg->nlmsg_flags, fbuf, sizeof(fbuf)),
+               nlmsg->nlmsg_seq, nlmsg->nlmsg_pid);
+
+       switch (nlmsg->nlmsg_type) {
+       /* Generic. */
+       case NLMSG_NOOP:
+               break;
+       case NLMSG_ERROR:
+               nlmsgerr = NLMSG_DATA(nlmsg);
+               zlog_debug("  nlmsgerr [error=(%d) %s]", nlmsgerr->error,
+                          strerror(-nlmsgerr->error));
+               break;
+       case NLMSG_DONE:
+               return;
+       case NLMSG_OVERRUN:
+               break;
+
+       /* RTM. */
+       case RTM_NEWLINK:
+       case RTM_DELLINK:
+       case RTM_SETLINK:
+               ifi = NLMSG_DATA(nlmsg);
+               zlog_debug(
+                       "  ifinfomsg [family=%d type=(%d) %s "
+                       "index=%d flags=0x%04x {%s}]",
+                       ifi->ifi_family, ifi->ifi_type,
+                       ifi_type2str(ifi->ifi_type), ifi->ifi_index,
+                       ifi->ifi_flags,
+                       if_flags2str(ifi->ifi_flags, ibuf, sizeof(ibuf)));
+               nllink_dump(ifi, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
+               break;
+       case RTM_GETLINK:
+               rtgen = NLMSG_DATA(nlmsg);
+               zlog_debug("  rtgen [family=(%d) %s]", rtgen->rtgen_family,
+                          af_type2str(rtgen->rtgen_family));
+               break;
+
+       case RTM_NEWROUTE:
+       case RTM_DELROUTE:
+       case RTM_GETROUTE:
+               rtm = NLMSG_DATA(nlmsg);
+               zlog_debug(
+                       "  rtmsg [family=(%d) %s dstlen=%d srclen=%d tos=%d "
+                       "table=%d protocol=(%d) %s scope=(%d) %s "
+                       "type=(%d) %s flags=0x%04x {%s}]",
+                       rtm->rtm_family, af_type2str(rtm->rtm_family),
+                       rtm->rtm_dst_len, rtm->rtm_src_len, rtm->rtm_tos,
+                       rtm->rtm_table, rtm->rtm_protocol,
+                       rtm_protocol2str(rtm->rtm_protocol), rtm->rtm_scope,
+                       rtm_scope2str(rtm->rtm_scope), rtm->rtm_type,
+                       rtm_type2str(rtm->rtm_type), rtm->rtm_flags,
+                       rtm_flags2str(rtm->rtm_flags, fbuf, sizeof(fbuf)));
+               nlroute_dump(rtm,
+                            nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
+               break;
+
+       case RTM_NEWNEIGH:
+       case RTM_DELNEIGH:
+               ndm = NLMSG_DATA(nlmsg);
+               zlog_debug(
+                       "  ndm [family=%d (%s) ifindex=%d state=0x%04x {%s} "
+                       "flags=0x%04x {%s} type=%d (%s)]",
+                       ndm->ndm_family, af_type2str(ndm->ndm_family),
+                       ndm->ndm_ifindex, ndm->ndm_state,
+                       neigh_state2str(ndm->ndm_state, ibuf, sizeof(ibuf)),
+                       ndm->ndm_flags,
+                       neigh_flags2str(ndm->ndm_flags, fbuf, sizeof(fbuf)),
+                       ndm->ndm_type, rtm_type2str(ndm->ndm_type));
+               nlneigh_dump(ndm,
+                            nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ndm)));
+               break;
+
+       case RTM_NEWADDR:
+       case RTM_DELADDR:
+               ifa = NLMSG_DATA(nlmsg);
+               zlog_debug(
+                       "  ifa [family=(%d) %s prefixlen=%d "
+                       "flags=0x%04x {%s} scope=%d index=%u]",
+                       ifa->ifa_family, af_type2str(ifa->ifa_family),
+                       ifa->ifa_prefixlen, ifa->ifa_flags,
+                       if_flags2str(ifa->ifa_flags, fbuf, sizeof(fbuf)),
+                       ifa->ifa_scope, ifa->ifa_index);
+               nlifa_dump(ifa, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
+               break;
+
+       case RTM_NEWNEXTHOP:
+       case RTM_DELNEXTHOP:
+       case RTM_GETNEXTHOP:
+               nhm = NLMSG_DATA(nlmsg);
+               zlog_debug(
+                       "  nhm [family=(%d) %s scope=(%d) %s "
+                       "protocol=(%d) %s flags=0x%08x {%s}]",
+                       nhm->nh_family, af_type2str(nhm->nh_family),
+                       nhm->nh_scope, rtm_scope2str(nhm->nh_scope),
+                       nhm->nh_protocol, rtm_protocol2str(nhm->nh_protocol),
+                       nhm->nh_flags,
+                       nh_flags2str(nhm->nh_flags, fbuf, sizeof(fbuf)));
+               nlnh_dump(nhm, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*nhm)));
+               break;
+
+       default:
+               break;
+       }
+
+       /*
+        * Try to get the next header. There should only be more
+        * messages if this header was flagged as MULTI, otherwise just
+        * end it here.
+        */
+       nlmsg = NLMSG_NEXT(nlmsg, msglen);
+       if (NLMSG_OK(nlmsg, msglen) == 0)
+               return;
+
+       goto next_header;
+}
+
+#endif /* NETLINK_DEBUG */
index 5bf47580a852c60bb16963b6e02a5e1d36369215..bf733e38f7b7caa312aaa2966b625031536ee32d 100644 (file)
@@ -43,6 +43,7 @@
 #include "zebra/debug.h"
 #include "zebra/interface.h"
 #include "zebra/zebra_dplane.h"
+#include "zebra/zebra_mpls.h"
 #include "zebra/zebra_router.h"
 #include "zebra/zebra_evpn.h"
 #include "zebra/zebra_evpn_mac.h"
@@ -74,9 +75,6 @@ struct fpm_nl_ctx {
        int socket;
        bool disabled;
        bool connecting;
-       bool nhg_complete;
-       bool rib_complete;
-       bool rmac_complete;
        bool use_nhg;
        struct sockaddr_storage addr;
 
@@ -103,6 +101,8 @@ struct fpm_nl_ctx {
        struct thread *t_dequeue;
 
        /* zebra events. */
+       struct thread *t_lspreset;
+       struct thread *t_lspwalk;
        struct thread *t_nhgreset;
        struct thread *t_nhgwalk;
        struct thread *t_ribreset;
@@ -155,6 +155,8 @@ enum fpm_nl_events {
        /* Reconnect request by our own code to avoid races. */
        FNE_INTERNAL_RECONNECT,
 
+       /* LSP walk finished. */
+       FNE_LSP_FINISHED,
        /* Next hop groups walk finished. */
        FNE_NHG_FINISHED,
        /* RIB walk finished. */
@@ -176,6 +178,8 @@ enum fpm_nl_events {
  */
 static int fpm_process_event(struct thread *t);
 static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx);
+static int fpm_lsp_send(struct thread *t);
+static int fpm_lsp_reset(struct thread *t);
 static int fpm_nhg_send(struct thread *t);
 static int fpm_nhg_reset(struct thread *t);
 static int fpm_rib_send(struct thread *t);
@@ -183,31 +187,6 @@ static int fpm_rib_reset(struct thread *t);
 static int fpm_rmac_send(struct thread *t);
 static int fpm_rmac_reset(struct thread *t);
 
-/*
- * Helper functions.
- */
-
-/**
- * Reorganizes the data on the buffer so it can fit more data.
- *
- * @param s stream pointer.
- */
-static void stream_pulldown(struct stream *s)
-{
-       size_t rlen = STREAM_READABLE(s);
-
-       /* No more data, so just move the pointers. */
-       if (rlen == 0) {
-               stream_reset(s);
-               return;
-       }
-
-       /* Move the available data to the beginning. */
-       memmove(s->data, &s->data[s->getp], rlen);
-       s->getp = 0;
-       s->endp = rlen;
-}
-
 /*
  * CLI.
  */
@@ -395,7 +374,6 @@ static int fpm_write_config(struct vty *vty)
        struct sockaddr_in *sin;
        struct sockaddr_in6 *sin6;
        int written = 0;
-       char addrstr[INET6_ADDRSTRLEN];
 
        if (gfnc->disabled)
                return written;
@@ -404,8 +382,7 @@ static int fpm_write_config(struct vty *vty)
        case AF_INET:
                written = 1;
                sin = (struct sockaddr_in *)&gfnc->addr;
-               inet_ntop(AF_INET, &sin->sin_addr, addrstr, sizeof(addrstr));
-               vty_out(vty, "fpm address %s", addrstr);
+               vty_out(vty, "fpm address %pI4", &sin->sin_addr);
                if (sin->sin_port != htons(SOUTHBOUND_DEFAULT_PORT))
                        vty_out(vty, " port %d", ntohs(sin->sin_port));
 
@@ -414,8 +391,7 @@ static int fpm_write_config(struct vty *vty)
        case AF_INET6:
                written = 1;
                sin6 = (struct sockaddr_in6 *)&gfnc->addr;
-               inet_ntop(AF_INET, &sin6->sin6_addr, addrstr, sizeof(addrstr));
-               vty_out(vty, "fpm address %s", addrstr);
+               vty_out(vty, "fpm address %pI6", &sin6->sin6_addr);
                if (sin6->sin6_port != htons(SOUTHBOUND_DEFAULT_PORT))
                        vty_out(vty, " port %d", ntohs(sin6->sin6_port));
 
@@ -449,6 +425,8 @@ static int fpm_connect(struct thread *t);
 static void fpm_reconnect(struct fpm_nl_ctx *fnc)
 {
        /* Cancel all zebra threads first. */
+       thread_cancel_async(zrouter.master, &fnc->t_lspreset, NULL);
+       thread_cancel_async(zrouter.master, &fnc->t_lspwalk, NULL);
        thread_cancel_async(zrouter.master, &fnc->t_nhgreset, NULL);
        thread_cancel_async(zrouter.master, &fnc->t_nhgwalk, NULL);
        thread_cancel_async(zrouter.master, &fnc->t_ribreset, NULL);
@@ -558,6 +536,13 @@ static int fpm_write(struct thread *t)
 
                fnc->connecting = false;
 
+               /*
+                * Starting with LSPs walk all FPM objects, marking them
+                * as unsent and then replaying them.
+                */
+               thread_add_timer(zrouter.master, fpm_lsp_reset, fnc, 0,
+                                &fnc->t_lspreset);
+
                /* Permit receiving messages now. */
                thread_add_read(fnc->fthread->master, fpm_read, fnc,
                                fnc->socket, &fnc->t_read);
@@ -677,13 +662,15 @@ static int fpm_connect(struct thread *t)
        thread_add_write(fnc->fthread->master, fpm_write, fnc, sock,
                         &fnc->t_write);
 
-       /* Mark all routes as unsent. */
-       if (fnc->use_nhg)
-               thread_add_timer(zrouter.master, fpm_nhg_reset, fnc, 0,
-                                &fnc->t_nhgreset);
-       else
-               thread_add_timer(zrouter.master, fpm_rib_reset, fnc, 0,
-                                &fnc->t_ribreset);
+       /*
+        * Starting with LSPs walk all FPM objects, marking them
+        * as unsent and then replaying them.
+        *
+        * If we are not connected, then delay the objects reset/send.
+        */
+       if (!fnc->connecting)
+               thread_add_timer(zrouter.master, fpm_lsp_reset, fnc, 0,
+                                &fnc->t_lspreset);
 
        return 0;
 }
@@ -790,6 +777,16 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
        case DPLANE_OP_LSP_INSTALL:
        case DPLANE_OP_LSP_UPDATE:
        case DPLANE_OP_LSP_DELETE:
+               rv = netlink_lsp_msg_encoder(ctx, nl_buf, sizeof(nl_buf));
+               if (rv <= 0) {
+                       zlog_err("%s: netlink_lsp_msg_encoder failed",
+                                __func__);
+                       return 0;
+               }
+
+               nl_buf_len += (size_t)rv;
+               break;
+
        case DPLANE_OP_PW_INSTALL:
        case DPLANE_OP_PW_UNINSTALL:
        case DPLANE_OP_ADDR_INSTALL:
@@ -866,6 +863,66 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
        return 0;
 }
 
+/*
+ * LSP walk/send functions
+ */
+struct fpm_lsp_arg {
+       struct zebra_dplane_ctx *ctx;
+       struct fpm_nl_ctx *fnc;
+       bool complete;
+};
+
+static int fpm_lsp_send_cb(struct hash_bucket *bucket, void *arg)
+{
+       zebra_lsp_t *lsp = bucket->data;
+       struct fpm_lsp_arg *fla = arg;
+
+       /* Skip entries which have already been sent */
+       if (CHECK_FLAG(lsp->flags, LSP_FLAG_FPM))
+               return HASHWALK_CONTINUE;
+
+       dplane_ctx_reset(fla->ctx);
+       dplane_ctx_lsp_init(fla->ctx, DPLANE_OP_LSP_INSTALL, lsp);
+
+       if (fpm_nl_enqueue(fla->fnc, fla->ctx) == -1) {
+               fla->complete = false;
+               return HASHWALK_ABORT;
+       }
+
+       /* Mark entry as sent */
+       SET_FLAG(lsp->flags, LSP_FLAG_FPM);
+       return HASHWALK_CONTINUE;
+}
+
+static int fpm_lsp_send(struct thread *t)
+{
+       struct fpm_nl_ctx *fnc = THREAD_ARG(t);
+       struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
+       struct fpm_lsp_arg fla;
+
+       fla.fnc = fnc;
+       fla.ctx = dplane_ctx_alloc();
+       fla.complete = true;
+
+       hash_walk(zvrf->lsp_table, fpm_lsp_send_cb, &fla);
+
+       dplane_ctx_fini(&fla.ctx);
+
+       if (fla.complete) {
+               WALK_FINISH(fnc, FNE_LSP_FINISHED);
+
+               /* Now move onto routes */
+               thread_add_timer(zrouter.master, fpm_nhg_reset, fnc, 0,
+                                &fnc->t_nhgreset);
+       } else {
+               /* Didn't finish - reschedule LSP walk */
+               thread_add_timer(zrouter.master, fpm_lsp_send, fnc, 0,
+                                &fnc->t_lspwalk);
+       }
+
+       return 0;
+}
+
 /*
  * Next hop walk/send functions.
  */
@@ -909,7 +966,8 @@ static int fpm_nhg_send(struct thread *t)
        fna.complete = true;
 
        /* Send next hops. */
-       hash_walk(zrouter.nhgs_id, fpm_nhg_send_cb, &fna);
+       if (fnc->use_nhg)
+               hash_walk(zrouter.nhgs_id, fpm_nhg_send_cb, &fna);
 
        /* `free()` allocated memory. */
        dplane_ctx_fini(&fna.ctx);
@@ -1067,7 +1125,6 @@ static int fpm_nhg_reset(struct thread *t)
 {
        struct fpm_nl_ctx *fnc = THREAD_ARG(t);
 
-       fnc->nhg_complete = false;
        hash_iterate(zrouter.nhgs_id, fpm_nhg_reset_cb, NULL);
 
        /* Schedule next step: send next hop groups. */
@@ -1076,6 +1133,29 @@ static int fpm_nhg_reset(struct thread *t)
        return 0;
 }
 
+/*
+ * Resets the LSP FPM flag so we send all LSPs again.
+ */
+static void fpm_lsp_reset_cb(struct hash_bucket *bucket, void *arg)
+{
+       zebra_lsp_t *lsp = bucket->data;
+
+       UNSET_FLAG(lsp->flags, LSP_FLAG_FPM);
+}
+
+static int fpm_lsp_reset(struct thread *t)
+{
+       struct fpm_nl_ctx *fnc = THREAD_ARG(t);
+       struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
+
+       hash_iterate(zvrf->lsp_table, fpm_lsp_reset_cb, NULL);
+
+       /* Schedule next step: send LSPs */
+       thread_add_event(zrouter.master, fpm_lsp_send, fnc, 0, &fnc->t_lspwalk);
+
+       return 0;
+}
+
 /**
  * Resets the RIB FPM flags so we send all routes again.
  */
@@ -1087,8 +1167,6 @@ static int fpm_rib_reset(struct thread *t)
        struct route_table *rt;
        rib_tables_iter_t rt_iter;
 
-       fnc->rib_complete = false;
-
        rt_iter.state = RIB_TABLES_ITER_S_INIT;
        while ((rt = rib_tables_iter_next(&rt_iter))) {
                for (rn = route_top(rt); rn; rn = srcdest_route_next(rn)) {
@@ -1128,7 +1206,6 @@ static int fpm_rmac_reset(struct thread *t)
 {
        struct fpm_nl_ctx *fnc = THREAD_ARG(t);
 
-       fnc->rmac_complete = false;
        hash_iterate(zrouter.l3vni_table, fpm_unset_l3vni_table, NULL);
 
        /* Schedule next event: send RMAC entries. */
@@ -1142,24 +1219,33 @@ static int fpm_process_queue(struct thread *t)
 {
        struct fpm_nl_ctx *fnc = THREAD_ARG(t);
        struct zebra_dplane_ctx *ctx;
-
-       frr_mutex_lock_autounlock(&fnc->ctxqueue_mutex);
+       bool no_bufs = false;
+       uint64_t processed_contexts = 0;
 
        while (true) {
                /* No space available yet. */
-               if (STREAM_WRITEABLE(fnc->obuf) < NL_PKT_BUF_SIZE)
+               if (STREAM_WRITEABLE(fnc->obuf) < NL_PKT_BUF_SIZE) {
+                       no_bufs = true;
                        break;
+               }
 
                /* Dequeue next item or quit processing. */
-               ctx = dplane_ctx_dequeue(&fnc->ctxqueue);
+               frr_with_mutex (&fnc->ctxqueue_mutex) {
+                       ctx = dplane_ctx_dequeue(&fnc->ctxqueue);
+               }
                if (ctx == NULL)
                        break;
 
-               fpm_nl_enqueue(fnc, ctx);
+               /*
+                * Intentionally ignoring the return value
+                * as that we are ensuring that we can write to
+                * the output data in the STREAM_WRITEABLE
+                * check above, so we can ignore the return
+                */
+               (void)fpm_nl_enqueue(fnc, ctx);
 
                /* Account the processed entries. */
-               atomic_fetch_add_explicit(&fnc->counters.dplane_contexts, 1,
-                                         memory_order_relaxed);
+               processed_contexts++;
                atomic_fetch_sub_explicit(&fnc->counters.ctxqueue_len, 1,
                                          memory_order_relaxed);
 
@@ -1167,13 +1253,24 @@ static int fpm_process_queue(struct thread *t)
                dplane_provider_enqueue_out_ctx(fnc->prov, ctx);
        }
 
-       /* Check for more items in the queue. */
-       if (atomic_load_explicit(&fnc->counters.ctxqueue_len,
-                                memory_order_relaxed)
-           > 0)
+       /* Update count of processed contexts */
+       atomic_fetch_add_explicit(&fnc->counters.dplane_contexts,
+                                 processed_contexts, memory_order_relaxed);
+
+       /* Re-schedule if we ran out of buffer space */
+       if (no_bufs)
                thread_add_timer(fnc->fthread->master, fpm_process_queue,
                                 fnc, 0, &fnc->t_dequeue);
 
+       /*
+        * Let the dataplane thread know if there are items in the
+        * output queue to be processed. Otherwise they may sit
+        * until the dataplane thread gets scheduled for new,
+        * unrelated work.
+        */
+       if (dplane_provider_out_ctx_queue_len(fnc->prov) > 0)
+               dplane_provider_work_ready();
+
        return 0;
 }
 
@@ -1223,20 +1320,18 @@ static int fpm_process_event(struct thread *t)
                if (IS_ZEBRA_DEBUG_FPM)
                        zlog_debug("%s: next hop groups walk finished",
                                   __func__);
-
-               fnc->nhg_complete = true;
                break;
        case FNE_RIB_FINISHED:
                if (IS_ZEBRA_DEBUG_FPM)
                        zlog_debug("%s: RIB walk finished", __func__);
-
-               fnc->rib_complete = true;
                break;
        case FNE_RMAC_FINISHED:
                if (IS_ZEBRA_DEBUG_FPM)
                        zlog_debug("%s: RMAC walk finished", __func__);
-
-               fnc->rmac_complete = true;
+               break;
+       case FNE_LSP_FINISHED:
+               if (IS_ZEBRA_DEBUG_FPM)
+                       zlog_debug("%s: LSP walk finished", __func__);
                break;
 
        default:
@@ -1276,6 +1371,8 @@ static int fpm_nl_start(struct zebra_dplane_provider *prov)
 static int fpm_nl_finish_early(struct fpm_nl_ctx *fnc)
 {
        /* Disable all events and close socket. */
+       THREAD_OFF(fnc->t_lspreset);
+       THREAD_OFF(fnc->t_lspwalk);
        THREAD_OFF(fnc->t_nhgreset);
        THREAD_OFF(fnc->t_nhgwalk);
        THREAD_OFF(fnc->t_ribreset);
@@ -1326,7 +1423,7 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov)
        struct zebra_dplane_ctx *ctx;
        struct fpm_nl_ctx *fnc;
        int counter, limit;
-       uint64_t cur_queue, peak_queue;
+       uint64_t cur_queue, peak_queue = 0, stored_peak_queue;
 
        fnc = dplane_provider_get_data(prov);
        limit = dplane_provider_get_work_limit(prov);
@@ -1340,22 +1437,22 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov)
                 * anyway.
                 */
                if (fnc->socket != -1 && fnc->connecting == false) {
-                       frr_mutex_lock_autounlock(&fnc->ctxqueue_mutex);
-                       dplane_ctx_enqueue_tail(&fnc->ctxqueue, ctx);
-
-                       /* Account the number of contexts. */
+                       /*
+                        * Update the number of queued contexts *before*
+                        * enqueueing, to ensure counter consistency.
+                        */
                        atomic_fetch_add_explicit(&fnc->counters.ctxqueue_len,
                                                  1, memory_order_relaxed);
+
+                       frr_with_mutex (&fnc->ctxqueue_mutex) {
+                               dplane_ctx_enqueue_tail(&fnc->ctxqueue, ctx);
+                       }
+
                        cur_queue = atomic_load_explicit(
                                &fnc->counters.ctxqueue_len,
                                memory_order_relaxed);
-                       peak_queue = atomic_load_explicit(
-                               &fnc->counters.ctxqueue_len_peak,
-                               memory_order_relaxed);
                        if (peak_queue < cur_queue)
-                               atomic_store_explicit(
-                                       &fnc->counters.ctxqueue_len_peak,
-                                       peak_queue, memory_order_relaxed);
+                               peak_queue = cur_queue;
                        continue;
                }
 
@@ -1363,12 +1460,23 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov)
                dplane_provider_enqueue_out_ctx(prov, ctx);
        }
 
+       /* Update peak queue length, if we just observed a new peak */
+       stored_peak_queue = atomic_load_explicit(
+               &fnc->counters.ctxqueue_len_peak, memory_order_relaxed);
+       if (stored_peak_queue < peak_queue)
+               atomic_store_explicit(&fnc->counters.ctxqueue_len_peak,
+                                     peak_queue, memory_order_relaxed);
+
        if (atomic_load_explicit(&fnc->counters.ctxqueue_len,
                                 memory_order_relaxed)
            > 0)
                thread_add_timer(fnc->fthread->master, fpm_process_queue,
                                 fnc, 0, &fnc->t_dequeue);
 
+       /* Ensure dataplane thread is rescheduled if we hit the work limit */
+       if (counter >= limit)
+               dplane_provider_work_ready();
+
        return 0;
 }
 
index a68873882d58027ededa8e7b8d51c40bb28bda78..e4dd745f42799f0ba62322db293d4e6917dbb8d4 100644 (file)
@@ -691,7 +691,7 @@ static int netlink_bridge_interface(struct nlmsghdr *h, int len, ns_id_t ns_id,
        return 0;
 }
 
-/* If the interface is and es bond member then it must follow EVPN's
+/* If the interface is an es bond member then it must follow EVPN's
  * protodown setting
  */
 static void netlink_proc_dplane_if_protodown(struct zebra_if *zif,
index ddad9c9e56e3d89da8c21a6dba01daba211b2706..4072eb1568be169f1ed916f1a7b19e5e81944b4e 100644 (file)
@@ -1428,6 +1428,14 @@ const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc,
        return pd_buf;
 }
 
+static inline bool if_is_protodown_applicable(struct interface *ifp)
+{
+       if (IS_ZEBRA_IF_BOND(ifp))
+               return false;
+
+       return true;
+}
+
 /* Interface's information print out to vty interface. */
 static void if_dump_vty(struct vty *vty, struct interface *ifp)
 {
@@ -1592,14 +1600,13 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
        }
 
        zebra_evpn_if_es_print(vty, zebra_if);
-       vty_out(vty, "  protodown: %s",
-               (zebra_if->flags & ZIF_FLAG_PROTODOWN) ? "on" : "off");
+       vty_out(vty, "  protodown: %s %s\n",
+               (zebra_if->flags & ZIF_FLAG_PROTODOWN) ? "on" : "off",
+               if_is_protodown_applicable(ifp) ? "" : "(n/a)");
        if (zebra_if->protodown_rc)
-               vty_out(vty, " rc: %s\n",
+               vty_out(vty, "  protodown reasons: %s\n",
                        zebra_protodown_rc_str(zebra_if->protodown_rc, pd_buf,
                                               sizeof(pd_buf)));
-       else
-               vty_out(vty, "\n");
 
        if (zebra_if->link_ifindex != IFINDEX_INTERNAL) {
                if (zebra_if->link)
index ab1a245e5e164a0c31b0f1e5269c47682e441968..8dcb477f10f55f7fc5812ed57763d5ab549336ac 100644 (file)
@@ -279,8 +279,12 @@ struct irdp_interface;
 /* Ethernet segment info used for setting up EVPN multihoming */
 struct zebra_evpn_es;
 struct zebra_es_if_info {
+       /* type-3 esi config */
        struct ethaddr sysmac;
        uint32_t lid; /* local-id; has to be unique per-ES-sysmac */
+
+       esi_t esi;
+
        uint16_t df_pref;
        struct zebra_evpn_es *es; /* local ES */
 };
index 76da00c61910e2328919033f7303cb45165f8dc4..bbe2fccc60ac1c9980f38b337f8faf40b197292c 100644 (file)
@@ -489,6 +489,19 @@ static void netlink_install_filter(int sock, __u32 pid, __u32 dplane_pid)
                             safe_strerror(errno));
 }
 
+void netlink_parse_rtattr_flags(struct rtattr **tb, int max,
+               struct rtattr *rta, int len, unsigned short flags)
+{
+       unsigned short type;
+
+       while (RTA_OK(rta, len)) {
+               type = rta->rta_type & ~flags;
+               if ((type <= max) && (!tb[type]))
+                       tb[type] = rta;
+               rta = RTA_NEXT(rta, len);
+       }
+}
+
 void netlink_parse_rtattr(struct rtattr **tb, int max, struct rtattr *rta,
                          int len)
 {
@@ -712,7 +725,11 @@ static ssize_t netlink_send_msg(const struct nlsock *nl, void *buf,
 
        if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_SEND) {
                zlog_debug("%s: >> netlink message dump [sent]", __func__);
+#ifdef NETLINK_DEBUG
+               nl_dump(buf, buflen);
+#else
                zlog_hexdump(buf, buflen);
+#endif /* NETLINK_DEBUG */
        }
 
        if (status == -1) {
@@ -770,7 +787,11 @@ static int netlink_recv_msg(const struct nlsock *nl, struct msghdr msg,
 
        if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV) {
                zlog_debug("%s: << netlink message dump [recv]", __func__);
+#ifdef NETLINK_DEBUG
+               nl_dump(buf, status);
+#else
                zlog_hexdump(buf, status);
+#endif /* NETLINK_DEBUG */
        }
 
        return status;
index 696f9be4f643a976b724c357381745bca04cb96d..a7b152b31bda7e20af98ebe26c4327f9327f2c09 100644 (file)
@@ -79,6 +79,9 @@ extern void nl_attr_rtnh_end(struct nlmsghdr *n, struct rtnexthop *rtnh);
 
 extern void netlink_parse_rtattr(struct rtattr **tb, int max,
                                 struct rtattr *rta, int len);
+extern void netlink_parse_rtattr_flags(struct rtattr **tb, int max,
+                                struct rtattr *rta, int len,
+                                unsigned short flags);
 extern void netlink_parse_rtattr_nested(struct rtattr **tb, int max,
                                        struct rtattr *rta);
 extern const char *nl_msg_type_to_str(uint16_t msg_type);
index 9d74aeca285090f995b55f1670080ca13f179514..adbdf54c1f763d640acdd7e2ea31bc9c5e424d78 100644 (file)
@@ -1107,7 +1107,7 @@ void rtm_read(struct rt_msghdr *rtm)
        if (rtm->rtm_type == RTM_CHANGE)
                rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL,
                           0, zebra_flags, &p, NULL, NULL, 0, RT_TABLE_MAIN, 0,
-                          0, true, false);
+                          0, true);
        if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD
            || rtm->rtm_type == RTM_CHANGE)
                rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0,
@@ -1116,7 +1116,7 @@ void rtm_read(struct rt_msghdr *rtm)
        else
                rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL,
                           0, zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, 0,
-                          0, true, false);
+                          0, true);
 }
 
 /* Interface function for the kernel routing table updates.  Support
index d312a661f3601bfe915f3e19778b5e4e5e102793..2634a333eec2f233a1daabd9587abebf0dfc2e72 100644 (file)
@@ -175,11 +175,9 @@ void label_manager_init(void)
 }
 
 /* alloc and fill a label chunk */
-struct label_manager_chunk *create_label_chunk(uint8_t proto,
-                                              unsigned short instance,
-                                              uint32_t session_id,
-                                              uint8_t keep, uint32_t start,
-                                              uint32_t end)
+struct label_manager_chunk *
+create_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id,
+                  uint8_t keep, uint32_t start, uint32_t end)
 {
        /* alloc chunk, fill it and return it */
        struct label_manager_chunk *lmc =
@@ -302,15 +300,13 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,
  * @param base Desired starting label of the chunk; if MPLS_LABEL_BASE_ANY it does not apply
  * @return Pointer to the assigned label chunk, or NULL if the request could not be satisfied
  */
-struct label_manager_chunk *assign_label_chunk(uint8_t proto,
-                                              unsigned short instance,
-                                              uint32_t session_id,
-                                              uint8_t keep, uint32_t size,
-                                              uint32_t base)
+struct label_manager_chunk *
+assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id,
+                  uint8_t keep, uint32_t size, uint32_t base)
 {
        struct label_manager_chunk *lmc;
        struct listnode *node;
-       uint32_t prev_end = 0;
+       uint32_t prev_end = MPLS_LABEL_UNRESERVED_MIN;
 
        /* handle chunks request with a specific base label */
        if (base != MPLS_LABEL_BASE_ANY)
@@ -332,8 +328,7 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
                }
                /* check if we hadve a "hole" behind us that we can squeeze into
                 */
-               if ((lmc->start > prev_end)
-                   && (lmc->start - prev_end >= size)) {
+               if ((lmc->start > prev_end) && (lmc->start - prev_end > size)) {
                        lmc = create_label_chunk(proto, instance, session_id,
                                                 keep, prev_end + 1,
                                                 prev_end + size);
@@ -390,6 +385,7 @@ static int label_manager_release_label_chunk(struct zserv *client,
  *
  * @param proto Daemon protocol of client, to identify the owner
  * @param instance Instance, to identify the owner
+ * @param session_id Zclient session ID, to identify the zclient session
  * @param start First label of the chunk
  * @param end Last label of the chunk
  * @return 0 on success, -1 otherwise
index 82154982c26bc23db31fb06ddef0c9d1f42131c7..8636c79219920aa1c7d570485d9a9e5d1f139f42 100644 (file)
@@ -95,11 +95,9 @@ int lm_get_chunk_response(struct label_manager_chunk *lmc, struct zserv *client,
                          vrf_id_t vrf_id);
 
 /* convenience function to allocate an lmc to be consumed by the above API */
-struct label_manager_chunk *create_label_chunk(uint8_t proto,
-                                              unsigned short instance,
-                                              uint32_t session_id,
-                                              uint8_t keep, uint32_t start,
-                                              uint32_t end);
+struct label_manager_chunk *
+create_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id,
+                  uint8_t keep, uint32_t start, uint32_t end);
 void delete_label_chunk(void *val);
 
 /* register/unregister callbacks for hooks */
@@ -115,11 +113,9 @@ struct label_manager {
 };
 
 void label_manager_init(void);
-struct label_manager_chunk *assign_label_chunk(uint8_t proto,
-                                              unsigned short instance,
-                                              uint32_t session_id,
-                                              uint8_t keep, uint32_t size,
-                                              uint32_t base);
+struct label_manager_chunk *
+assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id,
+                  uint8_t keep, uint32_t size, uint32_t base);
 int release_label_chunk(uint8_t proto, unsigned short instance,
                        uint32_t session_id, uint32_t start, uint32_t end);
 int lm_client_disconnect_cb(struct zserv *client);
index 1f075cfb4b59ff2db045abd229e433bbe9172844..370dbaa240acece56d7ba7aaea2f220a64cfec5a 100644 (file)
@@ -715,7 +715,7 @@ int zebra_del_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn,
        rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_TABLE,
                   re->table, re->flags, &p, NULL, re->nhe->nhg.nexthop,
                   re->nhe_id, zvrf->table_id, re->metric, re->distance,
-                  false, false);
+                  false);
 
        return 0;
 }
index 3bce62bfa8c2a4c226e553fe8020fd118cabd7d0..86766b8175730a338e2cad42f26f55321485d5d2 100644 (file)
@@ -84,6 +84,11 @@ struct rnh {
 
 PREDECL_LIST(re_list)
 
+struct opaque {
+       uint16_t length;
+       uint8_t data[];
+};
+
 struct route_entry {
        /* Link list. */
        struct re_list_item next;
@@ -157,6 +162,8 @@ struct route_entry {
 
        /* Distance. */
        uint8_t distance;
+
+       struct opaque *opaque;
 };
 
 #define RIB_SYSTEM_ROUTE(R) RSYSTEM_ROUTE((R)->type)
@@ -336,8 +343,8 @@ int route_entry_update_nhe(struct route_entry *re,
                           struct nhg_hash_entry *new_nhghe);
 
 /* NHG replace has happend, we have to update route_entry pointers to new one */
-void rib_handle_nhg_replace(struct nhg_hash_entry *old,
-                           struct nhg_hash_entry *new);
+void rib_handle_nhg_replace(struct nhg_hash_entry *old_entry,
+                           struct nhg_hash_entry *new_entry);
 
 #define route_entry_dump(prefix, src, re) _route_entry_dump(__func__, prefix, src, re)
 extern void _route_entry_dump(const char *func, union prefixconstptr pp,
@@ -386,7 +393,7 @@ extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
                       struct prefix *p, struct prefix_ipv6 *src_p,
                       const struct nexthop *nh, uint32_t nhe_id,
                       uint32_t table_id, uint32_t metric, uint8_t distance,
-                      bool fromkernel, bool connected_down);
+                      bool fromkernel);
 
 extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
                                     union g_addr *addr,
@@ -399,9 +406,8 @@ extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p,
                                           vrf_id_t vrf_id);
 
 extern void rib_update(enum rib_update_event event);
-extern void rib_update_vrf(vrf_id_t vrf_id, enum rib_update_event event);
 extern void rib_update_table(struct route_table *table,
-                            enum rib_update_event event);
+                            enum rib_update_event event, int rtype);
 extern int rib_sweep_route(struct thread *t);
 extern void rib_sweep_table(struct route_table *table);
 extern void rib_close_table(struct route_table *table);
index 7af60a389bd47f234b2a2f802889bf4bb86882d8..ac21978ee826f96a5c398f68b8966a35ca23a133 100644 (file)
@@ -522,7 +522,8 @@ DEFUN (show_ip_router_id,
                        inet_ntop(AF_INET6, &zvrf->rid6_user_assigned.u.prefix6,
                                  addr_name, sizeof(addr_name));
                } else {
-                       if (zvrf->rid_user_assigned.u.prefix4.s_addr == 0)
+                       if (zvrf->rid_user_assigned.u.prefix4.s_addr
+                           == INADDR_ANY)
                                return CMD_SUCCESS;
                        inet_ntop(AF_INET, &zvrf->rid_user_assigned.u.prefix4,
                                  addr_name, sizeof(addr_name));
index 3402edf467b3ec4d3b9358a49eabe73e68b883cb..d96d77e77c47d402345c59f93053ae4434bd8a3f 100644 (file)
 /* Re-defining as I am unable to include <linux/if_bridge.h> which has the
  * UAPI for MAC sync. */
 #ifndef _UAPI_LINUX_IF_BRIDGE_H
-/* FDB notification bits for NDA_NOTIFY:
- * - BR_FDB_NFY_STATIC - notify on activity/expire even for a static entry
- * - BR_FDB_NFY_INACTIVE - mark as inactive to avoid double notification,
- *                         used with BR_FDB_NFY_STATIC (kernel controlled)
- */
-enum {
-       BR_FDB_NFY_STATIC,
-       BR_FDB_NFY_INACTIVE,
-       BR_FDB_NFY_MAX
-};
+#define BR_SPH_LIST_SIZE 10
 #endif
 
 static vlanid_t filter_vlan = 0;
@@ -266,6 +257,10 @@ static inline int zebra2proto(int proto)
        case ZEBRA_ROUTE_NHG:
                proto = RTPROT_ZEBRA;
                break;
+       case ZEBRA_ROUTE_CONNECT:
+       case ZEBRA_ROUTE_KERNEL:
+               proto = RTPROT_KERNEL;
+               break;
        default:
                /*
                 * When a user adds a new protocol this will show up
@@ -869,7 +864,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
                if (nhe_id) {
                        rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
                                   &p, &src_p, NULL, nhe_id, table, metric,
-                                  distance, true, false);
+                                  distance, true);
                } else {
                        if (!tb[RTA_MULTIPATH]) {
                                struct nexthop nh;
@@ -879,13 +874,13 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
                                        gate, afi, vrf_id);
                                rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
                                           flags, &p, &src_p, &nh, 0, table,
-                                          metric, distance, true, false);
+                                          metric, distance, true);
                        } else {
                                /* XXX: need to compare the entire list of
                                 * nexthops here for NLM_F_APPEND stupidity */
                                rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
                                           flags, &p, &src_p, NULL, 0, table,
-                                          metric, distance, true, false);
+                                          metric, distance, true);
                        }
                }
        }
@@ -2761,25 +2756,40 @@ static ssize_t netlink_neigh_update_msg_encode(
                        return 0;
        }
 
-       if (nhg_id) {
-               if (!nl_attr_put32(&req->n, datalen, NDA_NH_ID, nhg_id))
-                       return 0;
-       }
        if (nfy) {
-               if (!nl_attr_put(&req->n, datalen, NDA_NOTIFY,
-                               &nfy_flags, sizeof(nfy_flags)))
+               struct rtattr *nest;
+
+               nest = nl_attr_nest(&req->n, datalen,
+                                   NDA_FDB_EXT_ATTRS | NLA_F_NESTED);
+               if (!nest)
+                       return 0;
+
+               if (!nl_attr_put(&req->n, datalen, NFEA_ACTIVITY_NOTIFY,
+                                &nfy_flags, sizeof(nfy_flags)))
+                       return 0;
+               if (!nl_attr_put(&req->n, datalen, NFEA_DONT_REFRESH, NULL, 0))
                        return 0;
+
+               nl_attr_nest_end(&req->n, nest);
        }
 
+
        if (ext) {
                if (!nl_attr_put(&req->n, datalen, NDA_EXT_FLAGS, &ext_flags,
                                 sizeof(ext_flags)))
                        return 0;
        }
 
-       ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN;
-       if (!nl_attr_put(&req->n, datalen, NDA_DST, &ip->ip.addr, ipa_len))
-               return 0;
+       if (nhg_id) {
+               if (!nl_attr_put32(&req->n, datalen, NDA_NH_ID, nhg_id))
+                       return 0;
+       } else {
+               ipa_len =
+                       IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN;
+               if (!nl_attr_put(&req->n, datalen, NDA_DST, &ip->ip.addr,
+                                ipa_len))
+                       return 0;
+       }
 
        if (op == DPLANE_OP_MAC_INSTALL || op == DPLANE_OP_MAC_DELETE) {
                vlanid_t vid = dplane_ctx_mac_get_vlan(ctx);
@@ -2848,7 +2858,8 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
         * validation of the fields.
         */
        memset(tb, 0, sizeof tb);
-       netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
+       netlink_parse_rtattr_flags(tb, NDA_MAX, NDA_RTA(ndm), len,
+                                  NLA_F_NESTED);
 
        if (!tb[NDA_LLADDR]) {
                if (IS_ZEBRA_DEBUG_KERNEL)
@@ -2890,14 +2901,21 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
        if (ndm->ndm_state & NUD_STALE)
                local_inactive = true;
 
-       if (tb[NDA_NOTIFY]) {
-               uint8_t nfy_flags;
+       if (tb[NDA_FDB_EXT_ATTRS]) {
+               struct rtattr *attr = tb[NDA_FDB_EXT_ATTRS];
+               struct rtattr *nfea_tb[NFEA_MAX + 1] = {0};
+
+               netlink_parse_rtattr_nested(nfea_tb, NFEA_MAX, attr);
+               if (nfea_tb[NFEA_ACTIVITY_NOTIFY]) {
+                       uint8_t nfy_flags;
 
-               dp_static = true;
-               nfy_flags = *(uint8_t *)RTA_DATA(tb[NDA_NOTIFY]);
-               /* local activity has not been detected on the entry */
-               if (nfy_flags & (1 << BR_FDB_NFY_INACTIVE))
-                       local_inactive = true;
+                       nfy_flags = *(uint8_t *)RTA_DATA(
+                               nfea_tb[NFEA_ACTIVITY_NOTIFY]);
+                       if (nfy_flags & FDB_NOTIFY_BIT)
+                               dp_static = true;
+                       if (nfy_flags & FDB_NOTIFY_INACTIVE_BIT)
+                               local_inactive = true;
+               }
        }
 
        if (IS_ZEBRA_DEBUG_KERNEL)
@@ -2953,8 +2971,9 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
                }
 
                if (IS_ZEBRA_IF_VXLAN(ifp))
-                       return zebra_vxlan_check_del_local_mac(ifp, br_if, &mac,
-                                                              vid);
+                       return zebra_vxlan_dp_network_mac_add(
+                               ifp, br_if, &mac, vid, nhg_id, sticky,
+                               !!(ndm->ndm_flags & NTF_EXT_LEARNED));
 
                return zebra_vxlan_local_mac_add_update(ifp, br_if, &mac, vid,
                                sticky, local_inactive, dp_static);
@@ -2982,8 +3001,7 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
        }
 
        if (IS_ZEBRA_IF_VXLAN(ifp))
-               return zebra_vxlan_check_readd_remote_mac(ifp, br_if, &mac,
-                                                         vid);
+               return zebra_vxlan_dp_network_mac_del(ifp, br_if, &mac, vid);
 
        return zebra_vxlan_local_mac_del(ifp, br_if, &mac, vid);
 }
@@ -3199,12 +3217,12 @@ ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data,
        } else {
                /* local mac */
                if (update_flags & DPLANE_MAC_SET_STATIC) {
-                       nfy_flags |= (1 << BR_FDB_NFY_STATIC);
+                       nfy_flags |= FDB_NOTIFY_BIT;
                        state |= NUD_NOARP;
                }
 
                if (update_flags & DPLANE_MAC_SET_INACTIVE)
-                       nfy_flags |= (1 << BR_FDB_NFY_INACTIVE);
+                       nfy_flags |= FDB_NOTIFY_INACTIVE_BIT;
 
                nfy = true;
        }
@@ -3297,6 +3315,8 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
        bool is_ext;
        bool is_router;
        bool local_inactive;
+       uint32_t ext_flags = 0;
+       bool dp_static = false;
 
        ndm = NLMSG_DATA(h);
 
@@ -3388,9 +3408,15 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
                is_ext = !!(ndm->ndm_flags & NTF_EXT_LEARNED);
                is_router = !!(ndm->ndm_flags & NTF_ROUTER);
 
+               if (tb[NDA_EXT_FLAGS]) {
+                       ext_flags = *(uint32_t *)RTA_DATA(tb[NDA_EXT_FLAGS]);
+                       if (ext_flags & NTF_E_MH_PEER_SYNC)
+                               dp_static = true;
+               }
+
                if (IS_ZEBRA_DEBUG_KERNEL)
                        zlog_debug(
-                               "Rx %s family %s IF %s(%u) vrf %s(%u) IP %s MAC %s state 0x%x flags 0x%x",
+                               "Rx %s family %s IF %s(%u) vrf %s(%u) IP %s MAC %s state 0x%x flags 0x%x ext_flags 0x%x",
                                nl_msg_type_to_str(h->nlmsg_type),
                                nl_family_to_str(ndm->ndm_family), ifp->name,
                                ndm->ndm_ifindex, VRF_LOGNAME(vrf), ifp->vrf_id,
@@ -3398,7 +3424,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
                                mac_present
                                        ? prefix_mac2str(&mac, buf, sizeof(buf))
                                        : "",
-                               ndm->ndm_state, ndm->ndm_flags);
+                               ndm->ndm_state, ndm->ndm_flags, ext_flags);
 
                /* If the neighbor state is valid for use, process as an add or
                 * update
@@ -3407,15 +3433,19 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
                 * in re-adding the neighbor if it is a valid "remote" neighbor.
                 */
                if (ndm->ndm_state & NUD_VALID) {
-                       local_inactive = !(ndm->ndm_state & NUD_LOCAL_ACTIVE);
+                       if (zebra_evpn_mh_do_adv_reachable_neigh_only())
+                               local_inactive =
+                                       !(ndm->ndm_state & NUD_LOCAL_ACTIVE);
+                       else
+                               /* If EVPN-MH is not enabled we treat STALE
+                                * neighbors as locally-active and advertise
+                                * them
+                                */
+                               local_inactive = false;
 
-                       /* XXX - populate dp-static based on the sync flags
-                        * in the kernel
-                        */
                        return zebra_vxlan_handle_kernel_neigh_update(
-                               ifp, link_if, &ip, &mac, ndm->ndm_state,
-                               is_ext, is_router, local_inactive,
-                               false /* dp_static */);
+                               ifp, link_if, &ip, &mac, ndm->ndm_state, is_ext,
+                               is_router, local_inactive, dp_static);
                }
 
                return zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
@@ -3686,12 +3716,12 @@ static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
                char buf2[ETHER_ADDR_STRLEN];
 
                zlog_debug(
-                       "Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x state 0x%x",
+                       "Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x state 0x%x %sext_flags 0x%x",
                        nl_msg_type_to_str(cmd), nl_family_to_str(family),
                        dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx),
                        ipaddr2str(ip, buf, sizeof(buf)),
                        mac ? prefix_mac2str(mac, buf2, sizeof(buf2)) : "null",
-                       flags, state);
+                       flags, state, ext ? "ext " : "", ext_flags);
        }
 
        return netlink_neigh_update_msg_encode(
index e1bb844785a6dc50be6c614509bf09f9bb332b54..4e41ff984bb4bf94528d0716826fdb2115e4c93d 100644 (file)
@@ -86,6 +86,9 @@ extern ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
                                          const struct zebra_dplane_ctx *ctx,
                                          void *buf, size_t buflen);
 
+extern ssize_t netlink_lsp_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf,
+                                      size_t buflen);
+
 extern int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id);
 extern int netlink_macfdb_read(struct zebra_ns *zns);
 extern int netlink_macfdb_read_for_bridge(struct zebra_ns *zns,
@@ -118,6 +121,29 @@ netlink_put_lsp_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
 extern enum netlink_msg_status
 netlink_put_pw_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
 
+#ifdef NETLINK_DEBUG
+const char *nlmsg_type2str(uint16_t type);
+const char *af_type2str(int type);
+const char *ifi_type2str(int type);
+const char *rta_type2str(int type);
+const char *rtm_type2str(int type);
+const char *rtm_protocol2str(int type);
+const char *rtm_scope2str(int type);
+const char *rtm_rta2str(int type);
+const char *neigh_rta2str(int type);
+const char *ifa_rta2str(int type);
+const char *nhm_rta2str(int type);
+const char *nlmsg_flags2str(uint16_t flags, char *buf, size_t buflen);
+const char *if_flags2str(uint32_t flags, char *buf, size_t buflen);
+const char *rtm_flags2str(uint32_t flags, char *buf, size_t buflen);
+const char *neigh_state2str(uint32_t flags, char *buf, size_t buflen);
+const char *neigh_flags2str(uint32_t flags, char *buf, size_t buflen);
+const char *ifa_flags2str(uint32_t flags, char *buf, size_t buflen);
+const char *nh_flags2str(uint32_t flags, char *buf, size_t buflen);
+
+void nl_dump(void *msg, size_t msglen);
+#endif /* NETLINK_DEBUG */
+
 #ifdef __cplusplus
 }
 #endif
index a63504992eb241171a1e1201039c8fae533d47e7..08a675ef3a108331ab6d4d962dfd4bac07e0df91 100644 (file)
@@ -79,7 +79,15 @@ netlink_rule_msg_encode(int cmd, const struct zebra_dplane_ctx *ctx,
        if (buflen < sizeof(*req))
                return 0;
        memset(req, 0, sizeof(*req));
-       family = PREFIX_FAMILY(src_ip);
+
+       /* Assume ipv4 if no src/dst set, we only support ipv4/ipv6 */
+       if (PREFIX_FAMILY(src_ip))
+               family = PREFIX_FAMILY(src_ip);
+       else if (PREFIX_FAMILY(dst_ip))
+               family = PREFIX_FAMILY(dst_ip);
+       else
+               family = AF_INET;
+
        bytelen = (family == AF_INET ? 4 : 16);
 
        req->n.nlmsg_type = cmd;
index c96a86cc7319db77bc01f27a840bffd6996bed15..464205f2f364aa77969f90e3eadad63415d6446d 100644 (file)
@@ -92,7 +92,6 @@ static int sample_process(struct zebra_dplane_provider *prov)
 static int init_sample_plugin(struct thread_master *tm)
 {
        int ret;
-       struct zebra_dplane_provider *prov = NULL;
 
        /* Note that we don't use or store the thread_master 'tm'. We
         * don't use the zebra main pthread: our plugin code will run in
index 4533d6bafcc9099256a41671b9c068b44cc1990a..f842a8c0f33e674567bc9cf3ab1a64b50afc3935 100644 (file)
@@ -40,6 +40,11 @@ if LINUX
 module_LTLIBRARIES += zebra/zebra_cumulus_mlag.la
 endif
 
+# Dataplane sample plugin
+if DEV_BUILD
+module_LTLIBRARIES += zebra/dplane_sample_plugin.la
+endif
+
 man8 += $(MANBUILD)/frr-zebra.8
 ## endif ZEBRA
 endif
@@ -206,6 +211,12 @@ zebra/zebra_fpm_dt.lo: fpm/fpm.pb-c.h qpb/qpb.pb-c.h
 endif
 endif
 
+# Sample dataplane plugin
+if DEV_BUILD
+zebra_dplane_sample_plugin_la_SOURCES = zebra/sample_plugin.c
+zebra_dplane_sample_plugin_la_LDFLAGS = -module -shared -avoid-version -export-dynamic
+endif
+
 nodist_zebra_zebra_SOURCES = \
        yang/frr-zebra.yang.c \
        # end
@@ -222,3 +233,9 @@ zebra_dplane_fpm_nl_la_LIBADD  =
 
 vtysh_scan += $(top_srcdir)/zebra/dplane_fpm_nl.c
 endif
+
+if NETLINK_DEBUG
+zebra_zebra_SOURCES += \
+       zebra/debug_nl.c \
+       # end
+endif
index 1d68019909d6a669c0e7c65ab4730cfa71f3ba27..90c6a24e7b6621d3bfb535cd2443394f1b590387 100644 (file)
@@ -764,7 +764,11 @@ static int route_notify_internal(const struct prefix *p, int type,
                        "Notifying Owner: %s about prefix %pFX(%u) %d vrf: %u",
                        zebra_route_string(type), p, table_id, note, vrf_id);
 
-       s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+       /* We're just allocating a small-ish buffer here, since we only
+        * encode a small amount of data.
+        */
+       s = stream_new(ZEBRA_SMALL_PACKET_SIZE);
+
        stream_reset(s);
 
        zclient_create_header(s, ZEBRA_ROUTE_NOTIFY_OWNER, vrf_id);
@@ -991,7 +995,6 @@ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw)
 int zsend_assign_label_chunk_response(struct zserv *client, vrf_id_t vrf_id,
                                      struct label_manager_chunk *lmc)
 {
-       int ret;
        struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
 
        zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id);
@@ -1011,16 +1014,13 @@ int zsend_assign_label_chunk_response(struct zserv *client, vrf_id_t vrf_id,
        /* Write packet size. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
-       ret = writen(client->sock, s->data, stream_get_endp(s));
-       stream_free(s);
-       return ret;
+       return zserv_send_message(client, s);
 }
 
 /* Send response to a label manager connect request to client */
 int zsend_label_manager_connect_response(struct zserv *client, vrf_id_t vrf_id,
                                         unsigned short result)
 {
-       int ret;
        struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
 
        zclient_create_header(s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id);
@@ -1037,10 +1037,7 @@ int zsend_label_manager_connect_response(struct zserv *client, vrf_id_t vrf_id,
        /* Write packet size. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
-       ret = writen(client->sock, s->data, stream_get_endp(s));
-       stream_free(s);
-
-       return ret;
+       return zserv_send_message(client, s);
 }
 
 /* Send response to a get table chunk request to client */
@@ -1976,6 +1973,13 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
        if (CHECK_FLAG(api.message, ZAPI_MESSAGE_MTU))
                re->mtu = api.mtu;
 
+       if (CHECK_FLAG(api.message, ZAPI_MESSAGE_OPAQUE)) {
+               re->opaque = XMALLOC(MTYPE_OPAQUE,
+                                    sizeof(struct opaque) + api.opaque.length);
+               re->opaque->length = api.opaque.length;
+               memcpy(re->opaque->data, api.opaque.data, re->opaque->length);
+       }
+
        afi = family2afi(api.prefix.family);
        if (afi != AFI_IP6 && CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) {
                flog_warn(EC_ZEBRA_RX_SRCDEST_WRONG_AFI,
@@ -2076,7 +2080,7 @@ static void zread_route_del(ZAPI_HANDLER_ARGS)
 
        rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance,
                   api.flags, &api.prefix, src_p, NULL, 0, table_id, api.metric,
-                  api.distance, false, false);
+                  api.distance, false);
 
        /* Stats */
        switch (api.prefix.family) {
@@ -2518,6 +2522,22 @@ int zsend_sr_policy_notify_status(uint32_t color, struct ipaddr *endpoint,
        return zserv_send_message(client, s);
 }
 
+/* Send client close notify to client */
+int zsend_client_close_notify(struct zserv *client, struct zserv *closed_client)
+{
+       struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+       zclient_create_header(s, ZEBRA_CLIENT_CLOSE_NOTIFY, VRF_DEFAULT);
+
+       stream_putc(s, closed_client->proto);
+       stream_putw(s, closed_client->instance);
+       stream_putl(s, closed_client->session_id);
+
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zserv_send_message(client, s);
+}
+
 /* Send response to a table manager connect request to client */
 static void zread_table_manager_connect(struct zserv *client,
                                        struct stream *msg, vrf_id_t vrf_id)
index efc52059b665bb059cba8f376e51dd58d7339872..9822d7202279ed31f6349fcb8c58db319cdd3eb6 100644 (file)
@@ -105,6 +105,9 @@ extern int zsend_sr_policy_notify_status(uint32_t color,
                                         struct ipaddr *endpoint, char *name,
                                         int status);
 
+extern int zsend_client_close_notify(struct zserv *client,
+                                    struct zserv *closed_client);
+
 #ifdef __cplusplus
 }
 #endif
index 22cc234b2f6da517f3680922dff304b3ac274b60..db2b9e002eca6465d28f316f63e353e3ace01fc7 100644 (file)
@@ -2014,16 +2014,6 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
        for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop)) {
                UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
 
-               /* Check for available encapsulations. */
-               if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE))
-                       continue;
-
-               zl3vni = zl3vni_from_vrf(nexthop->vrf_id);
-               if (zl3vni && is_l3vni_oper_up(zl3vni)) {
-                       nexthop->nh_encap_type = NET_VXLAN;
-                       nexthop->nh_encap.vni = zl3vni->vni;
-               }
-
                /* Optionally capture extra interface info while we're in the
                 * main zebra pthread - a plugin has to ask for this info.
                 */
@@ -2044,6 +2034,16 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
                                                  if_extra, link);
                        }
                }
+
+               /* Check for available evpn encapsulations. */
+               if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE))
+                       continue;
+
+               zl3vni = zl3vni_from_vrf(nexthop->vrf_id);
+               if (zl3vni && is_l3vni_oper_up(zl3vni)) {
+                       nexthop->nh_encap_type = NET_VXLAN;
+                       nexthop->nh_encap.vni = zl3vni->vni;
+               }
        }
 
        /* Don't need some info when capturing a system notification */
@@ -3684,7 +3684,7 @@ int dplane_show_helper(struct vty *vty, bool detailed)
 int dplane_show_provs_helper(struct vty *vty, bool detailed)
 {
        struct zebra_dplane_provider *prov;
-       uint64_t in, in_max, out, out_max;
+       uint64_t in, in_q, in_max, out, out_q, out_max;
 
        vty_out(vty, "Zebra dataplane providers:\n");
 
@@ -3697,17 +3697,20 @@ int dplane_show_provs_helper(struct vty *vty, bool detailed)
 
                in = atomic_load_explicit(&prov->dp_in_counter,
                                          memory_order_relaxed);
+               in_q = atomic_load_explicit(&prov->dp_in_queued,
+                                           memory_order_relaxed);
                in_max = atomic_load_explicit(&prov->dp_in_max,
                                              memory_order_relaxed);
                out = atomic_load_explicit(&prov->dp_out_counter,
                                           memory_order_relaxed);
+               out_q = atomic_load_explicit(&prov->dp_out_queued,
+                                            memory_order_relaxed);
                out_max = atomic_load_explicit(&prov->dp_out_max,
                                               memory_order_relaxed);
 
-               vty_out(vty,
-                       "%s (%u): in: %" PRIu64 ", q_max: %" PRIu64
-                       ", out: %" PRIu64 ", q_max: %" PRIu64 "\n",
-                       prov->dp_name, prov->dp_id, in, in_max, out, out_max);
+               vty_out(vty, "%s (%u): in: %"PRIu64", q: %"PRIu64", q_max: %"PRIu64", out: %"PRIu64", q: %"PRIu64", q_max: %"PRIu64"\n",
+                       prov->dp_name, prov->dp_id, in, in_q, in_max,
+                       out, out_q, out_max);
 
                DPLANE_LOCK();
                prov = TAILQ_NEXT(prov, dp_prov_link);
@@ -3900,17 +3903,36 @@ int dplane_provider_dequeue_in_list(struct zebra_dplane_provider *prov,
        return ret;
 }
 
+uint32_t dplane_provider_out_ctx_queue_len(struct zebra_dplane_provider *prov)
+{
+       return atomic_load_explicit(&(prov->dp_out_counter),
+                                   memory_order_relaxed);
+}
+
 /*
  * Enqueue and maintain associated counter
  */
 void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov,
                                     struct zebra_dplane_ctx *ctx)
 {
+       uint64_t curr, high;
+
        dplane_provider_lock(prov);
 
        TAILQ_INSERT_TAIL(&(prov->dp_ctx_out_q), ctx,
                          zd_q_entries);
 
+       /* Maintain out-queue counters */
+       atomic_fetch_add_explicit(&(prov->dp_out_queued), 1,
+                                 memory_order_relaxed);
+       curr = atomic_load_explicit(&prov->dp_out_queued,
+                                   memory_order_relaxed);
+       high = atomic_load_explicit(&prov->dp_out_max,
+                                   memory_order_relaxed);
+       if (curr > high)
+               atomic_store_explicit(&prov->dp_out_max, curr,
+                                     memory_order_relaxed);
+
        dplane_provider_unlock(prov);
 
        atomic_fetch_add_explicit(&(prov->dp_out_counter), 1,
@@ -4327,6 +4349,49 @@ static void dplane_provider_init(void)
 #endif /* DPLANE_TEST_PROVIDER */
 }
 
+/*
+ * Allow zebra code to walk the queue of pending contexts, evaluate each one
+ * using a callback function. If the function returns 'true', the context
+ * will be dequeued and freed without being processed.
+ */
+int dplane_clean_ctx_queue(bool (*context_cb)(struct zebra_dplane_ctx *ctx,
+                                             void *arg), void *val)
+{
+       struct zebra_dplane_ctx *ctx, *temp;
+       struct dplane_ctx_q work_list;
+
+       TAILQ_INIT(&work_list);
+
+       if (context_cb == NULL)
+               goto done;
+
+       /* Walk the pending context queue under the dplane lock. */
+       DPLANE_LOCK();
+
+       TAILQ_FOREACH_SAFE(ctx, &zdplane_info.dg_update_ctx_q, zd_q_entries,
+                          temp) {
+               if (context_cb(ctx, val)) {
+                       TAILQ_REMOVE(&zdplane_info.dg_update_ctx_q, ctx,
+                                    zd_q_entries);
+                       TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries);
+               }
+       }
+
+       DPLANE_UNLOCK();
+
+       /* Now free any contexts selected by the caller, without holding
+        * the lock.
+        */
+       TAILQ_FOREACH_SAFE(ctx, &work_list, zd_q_entries, temp) {
+               TAILQ_REMOVE(&work_list, ctx, zd_q_entries);
+               dplane_ctx_fini(&ctx);
+       }
+
+done:
+
+       return 0;
+}
+
 /* Indicates zebra shutdown/exit is in progress. Some operations may be
  * simplified or skipped during shutdown processing.
  */
@@ -4488,6 +4553,7 @@ static int dplane_thread_loop(struct thread *event)
        struct zebra_dplane_ctx *ctx, *tctx;
        int limit, counter, error_counter;
        uint64_t curr, high;
+       bool reschedule = false;
 
        /* Capture work limit per cycle */
        limit = zdplane_info.dg_updates_per_cycle;
@@ -4624,6 +4690,9 @@ static int dplane_thread_loop(struct thread *event)
 
                dplane_provider_unlock(prov);
 
+               if (counter >= limit)
+                       reschedule = true;
+
                if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
                        zlog_debug("dplane dequeues %d completed work from provider %s",
                                   counter, dplane_provider_get_name(prov));
@@ -4634,6 +4703,13 @@ static int dplane_thread_loop(struct thread *event)
                DPLANE_UNLOCK();
        }
 
+       /*
+        * We hit the work limit while processing at least one provider's
+        * output queue - ensure we come back and finish it.
+        */
+       if (reschedule)
+               dplane_provider_work_ready();
+
        /* After all providers have been serviced, enqueue any completed
         * work and any errors back to zebra so it can process the results.
         */
index 1b2ea9d96bca2f77a42e3c128c845c5979187e14..595d3fe562915524bece6f2ee95e1c286e669667 100644 (file)
@@ -216,6 +216,15 @@ struct zebra_dplane_ctx *dplane_ctx_alloc(void);
  */
 void dplane_ctx_reset(struct zebra_dplane_ctx *ctx);
 
+/*
+ * Allow zebra code to walk the queue of pending contexts, evaluate each one
+ * using a callback function. The caller can supply an optional void* arg also.
+ * If the function returns 'true', the context will be dequeued and freed
+ * without being processed.
+ */
+int dplane_clean_ctx_queue(bool (*context_cb)(struct zebra_dplane_ctx *ctx,
+                                             void *arg), void *val);
+
 /* Return a dataplane results context block after use; the caller's pointer will
  * be cleared.
  */
@@ -754,6 +763,9 @@ struct zebra_dplane_ctx *dplane_provider_dequeue_in_ctx(
 int dplane_provider_dequeue_in_list(struct zebra_dplane_provider *prov,
                                    struct dplane_ctx_q *listp);
 
+/* Current completed work queue length */
+uint32_t dplane_provider_out_ctx_queue_len(struct zebra_dplane_provider *prov);
+
 /* Enqueue completed work, maintain associated counter and locking */
 void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov,
                                     struct zebra_dplane_ctx *ctx);
index b75708031e2343145ce46586767f83b74efcbc25..29b271425dc35b00a1e68e01162760a6a64fc997 100644 (file)
@@ -310,12 +310,6 @@ static struct log_ref ferr_zebra_err[] = {
                .suggestion =
                        "Check to see if the nexthop group on the route you tried to install is valid."
        },
-       {
-               .code = EC_ZEBRA_IF_LOOKUP_FAILED,
-               .title = "Zebra interface lookup failed",
-               .description = "Zebra attempted to look up a interface for a particular vrf_id and interface index, but didn't find anything.",
-               .suggestion = "If you entered a command to trigger this error, make sure you entered the arguments correctly. Check your config file for any potential errors. If these look correct, seek help.",
-       },
        {
                .code = EC_ZEBRA_NS_NO_DEFAULT,
                .title = "Zebra NameSpace failed to find Default",
index 03953ed17f78875566ad2ebfab50afb267ad9be4..fc0382a6cdaedbf72f2ecf4897f131267522336c 100644 (file)
@@ -75,7 +75,6 @@ enum zebra_log_refs {
        EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
        EC_ZEBRA_NHG_SYNC,
        EC_ZEBRA_NHG_FIB_UPDATE,
-       EC_ZEBRA_IF_LOOKUP_FAILED,
        EC_ZEBRA_NS_NO_DEFAULT,
        EC_ZEBRA_PBR_RULE_UPDATE,
        /* warnings */
index 6722af117cbe6dfba5e052884b2fb165195f39b9..b232c664bc828e47777a3830e3f294efbf07f8a8 100644 (file)
@@ -1046,6 +1046,9 @@ int zebra_evpn_del(zebra_evpn_t *zevpn)
        hash_free(zevpn->mac_table);
        zevpn->mac_table = NULL;
 
+       /* Remove references to the zevpn in the MH databases */
+       if (zevpn->vxlan_if)
+               zebra_evpn_vxl_evpn_set(zevpn->vxlan_if->info, zevpn, false);
        zebra_evpn_es_evi_cleanup(zevpn);
 
        /* Free the EVPN hash entry and allocated memory. */
@@ -1333,7 +1336,8 @@ zebra_evpn_process_sync_macip_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
        if (ipa_len) {
                n = zebra_evpn_neigh_lookup(zevpn, ipaddr);
                if (n
-                   && !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq))
+                   && !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq,
+                                                      true))
                        return;
        }
 
@@ -1364,7 +1368,8 @@ void process_remote_macip_add(vni_t vni, struct ethaddr *macaddr,
        /* Locate EVPN hash entry - expected to exist. */
        zevpn = zebra_evpn_lookup(vni);
        if (!zevpn) {
-               zlog_warn("Unknown VNI %u upon remote MACIP ADD", vni);
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("Unknown VNI %u upon remote MACIP ADD", vni);
                return;
        }
 
index 4a2d8db42237a5632b10e7f9dc74747bbf090d5e..6753bf520c2b9116d339ff81fa99c91854516899 100644 (file)
@@ -29,6 +29,7 @@
 #include "prefix.h"
 #include "vlan.h"
 #include "json.h"
+#include "printfrr.h"
 
 #include "zebra/zserv.h"
 #include "zebra/debug.h"
@@ -108,9 +109,6 @@ int zebra_evpn_rem_mac_install(zebra_evpn_t *zevpn, zebra_mac_t *mac,
        uint32_t nhg_id;
        struct in_addr vtep_ip;
 
-       if (!(mac->flags & ZEBRA_MAC_REMOTE))
-               return 0;
-
        zif = zevpn->vxlan_if->info;
        if (!zif)
                return -1;
@@ -155,7 +153,8 @@ int zebra_evpn_rem_mac_install(zebra_evpn_t *zevpn, zebra_mac_t *mac,
 /*
  * Uninstall remote MAC from the forwarding plane.
  */
-int zebra_evpn_rem_mac_uninstall(zebra_evpn_t *zevpn, zebra_mac_t *mac)
+int zebra_evpn_rem_mac_uninstall(zebra_evpn_t *zevpn, zebra_mac_t *mac,
+                                bool force)
 {
        const struct zebra_if *zif, *br_zif;
        const struct zebra_l2info_vxlan *vxl;
@@ -164,8 +163,9 @@ int zebra_evpn_rem_mac_uninstall(zebra_evpn_t *zevpn, zebra_mac_t *mac)
        vlanid_t vid;
        enum zebra_dplane_result res;
 
-       if (!(mac->flags & ZEBRA_MAC_REMOTE))
-               return 0;
+       /* If the MAC was not installed there is no need to uninstall it */
+       if (!force && mac->es && !(mac->es->flags & ZEBRA_EVPNES_NHG_ACTIVE))
+               return -1;
 
        if (!zevpn->vxlan_if) {
                if (IS_ZEBRA_DEBUG_VXLAN)
@@ -216,7 +216,7 @@ void zebra_evpn_deref_ip2mac(zebra_evpn_t *zevpn, zebra_mac_t *mac)
         */
        if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
            && remote_neigh_count(mac) == 0) {
-               zebra_evpn_rem_mac_uninstall(zevpn, mac);
+               zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/);
                zebra_evpn_es_mac_deref_entry(mac);
                UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
        }
@@ -255,6 +255,37 @@ static void zebra_evpn_mac_get_access_info(zebra_mac_t *mac,
        }
 }
 
+#define MAC_BUF_SIZE 256
+static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac_t_ *mac, char *buf,
+                                           size_t len)
+{
+       if (mac->flags == 0) {
+               snprintfrr(buf, len, "None ");
+               return buf;
+       }
+
+       snprintfrr(
+               buf, len, "%s%s%s%s%s%s%s%s%s%s%s%s",
+               CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) ? "LOC " : "",
+               CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ? "REM " : "",
+               CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) ? "AUTO " : "",
+               CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? "STICKY " : "",
+               CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_RMAC) ? "REM Router "
+                                                             : "",
+               CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) ? "Default GW " : "",
+               CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? "REM DEF GW "
+                                                               : "",
+               CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) ? "DUP " : "",
+               CHECK_FLAG(mac->flags, ZEBRA_MAC_FPM_SENT) ? "FPM " : "",
+               CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE) ? "LOC Active "
+                                                                : "",
+               CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY " : "",
+               CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)
+                       ? "LOC Inactive "
+                       : "");
+       return buf;
+}
+
 static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t)
 {
        struct zebra_vrf *zvrf = NULL;
@@ -279,12 +310,17 @@ static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t)
        if (!mac)
                return 0;
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
+       if (IS_ZEBRA_DEBUG_VXLAN) {
+               char mac_buf[MAC_BUF_SIZE];
+
                zlog_debug(
-                       "%s: duplicate addr mac %s flags 0x%x learn count %u host count %u auto recovery expired",
+                       "%s: duplicate addr mac %s flags %slearn count %u host count %u auto recovery expired",
                        __func__,
                        prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
-                       mac->flags, mac->dad_count, listcount(mac->neigh_list));
+                       zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                      sizeof(mac_buf)),
+                       mac->dad_count, listcount(mac->neigh_list));
+       }
 
        /* Remove all IPs as duplicate associcated with this MAC */
        for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
@@ -343,7 +379,7 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
        char buf1[INET6_ADDRSTRLEN];
        bool reset_params = false;
 
-       if (!(zvrf->dup_addr_detect && do_dad))
+       if (!(zebra_evpn_do_dup_addr_detect(zvrf) && do_dad))
                return;
 
        /* MAC is detected as duplicate,
@@ -351,14 +387,17 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
         * Remote MAC event -> hold on installing it.
         */
        if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
-               if (IS_ZEBRA_DEBUG_VXLAN)
+               if (IS_ZEBRA_DEBUG_VXLAN) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "%s: duplicate addr MAC %s flags 0x%x skip update to client, learn count %u recover time %u",
+                               "%s: duplicate addr MAC %s flags %sskip update to client, learn count %u recover time %u",
                                __func__,
                                prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
-                               mac->flags, mac->dad_count,
-                               zvrf->dad_freeze_time);
-
+                               zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                              sizeof(mac_buf)),
+                               mac->dad_count, zvrf->dad_freeze_time);
+               }
                /* For duplicate MAC do not update
                 * client but update neigh due to
                 * this MAC update.
@@ -386,12 +425,17 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
        }
 
        if (reset_params) {
-               if (IS_ZEBRA_DEBUG_VXLAN)
+               if (IS_ZEBRA_DEBUG_VXLAN) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "%s: duplicate addr MAC %s flags 0x%x detection time passed, reset learn count %u",
+                               "%s: duplicate addr MAC %s flags %sdetection time passed, reset learn count %u",
                                __func__,
                                prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
-                               mac->flags, mac->dad_count);
+                               zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                              sizeof(mac_buf)),
+                               mac->dad_count);
+               }
 
                mac->dad_count = 0;
                /* Start dup. addr detection (DAD) start time,
@@ -453,13 +497,18 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
                /* Start auto recovery timer for this MAC */
                THREAD_OFF(mac->dad_mac_auto_recovery_timer);
                if (zvrf->dad_freeze && zvrf->dad_freeze_time) {
-                       if (IS_ZEBRA_DEBUG_VXLAN)
+                       if (IS_ZEBRA_DEBUG_VXLAN) {
+                               char mac_buf[MAC_BUF_SIZE];
+
                                zlog_debug(
-                                       "%s: duplicate addr MAC %s flags 0x%x auto recovery time %u start",
+                                       "%s: duplicate addr MAC %s flags %sauto recovery time %u start",
                                        __func__,
                                        prefix_mac2str(&mac->macaddr, buf,
                                                       sizeof(buf)),
-                                       mac->flags, zvrf->dad_freeze_time);
+                                       zebra_evpn_zebra_mac_flag_dump(
+                                               mac, mac_buf, sizeof(mac_buf)),
+                                       zvrf->dad_freeze_time);
+                       }
 
                        thread_add_timer(zrouter.master,
                                         zebra_evpn_dad_mac_auto_recovery_exp,
@@ -695,7 +744,7 @@ void zebra_evpn_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
 }
 
 static char *zebra_evpn_print_mac_flags(zebra_mac_t *mac, char *flags_buf,
-       uint32_t flags_buf_sz)
+                                       size_t flags_buf_sz)
 {
        snprintf(flags_buf, flags_buf_sz, "%s%s%s%s",
                        mac->sync_neigh_cnt ?
@@ -904,14 +953,19 @@ int zebra_evpn_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
        /* Write packet size. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
+       if (IS_ZEBRA_DEBUG_VXLAN) {
+               char flag_buf[MACIP_BUF_SIZE];
+
                zlog_debug(
-                       "Send MACIP %s f 0x%x MAC %s IP %s seq %u L2-VNI %u ESI %s to %s",
-                       (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", flags,
+                       "Send MACIP %s f %s MAC %s IP %s seq %u L2-VNI %u ESI %s to %s",
+                       (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
+                       zclient_evpn_dump_macip_flags(flags, flag_buf,
+                                                     sizeof(flag_buf)),
                        prefix_mac2str(macaddr, buf, sizeof(buf)),
                        ipaddr2str(ip, buf2, sizeof(buf2)), seq, vni,
                        es ? es->esi_str : "-",
                        zebra_route_string(client->proto));
+       }
 
        if (cmd == ZEBRA_MACIP_ADD)
                client->macipadd_cnt++;
@@ -983,10 +1037,12 @@ zebra_mac_t *zebra_evpn_mac_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr)
        mac->uptime = monotime(NULL);
        if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
                char buf[ETHER_ADDR_STRLEN];
+               char mac_buf[MAC_BUF_SIZE];
 
-               zlog_debug("%s: MAC %s flags 0x%x", __func__,
+               zlog_debug("%s: MAC %s flags %s", __func__,
                           prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
-                          mac->flags);
+                          zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                         sizeof(mac_buf)));
        }
        return mac;
 }
@@ -1000,12 +1056,22 @@ int zebra_evpn_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac)
 
        if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
                char buf[ETHER_ADDR_STRLEN];
+               char mac_buf[MAC_BUF_SIZE];
 
-               zlog_debug("%s: MAC %s flags 0x%x", __func__,
+               zlog_debug("%s: MAC %s flags %s", __func__,
                           prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
-                          mac->flags);
+                          zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                         sizeof(mac_buf)));
        }
 
+       /* If the MAC is freed before the neigh we will end up
+        * with a stale pointer against the neigh
+        */
+       if (!list_isempty(mac->neigh_list))
+               zlog_warn("%s: MAC %pEA flags 0x%x neigh list not empty %d",
+                         __func__, &mac->macaddr, mac->flags,
+                         listcount(mac->neigh_list));
+
        /* force de-ref any ES entry linked to the MAC */
        zebra_evpn_es_mac_deref_entry(mac);
 
@@ -1040,11 +1106,13 @@ static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx,
                 && !listcount(mac->neigh_list)) {
                if (IS_ZEBRA_DEBUG_VXLAN) {
                        char buf[ETHER_ADDR_STRLEN];
+                       char mac_buf[MAC_BUF_SIZE];
 
                        zlog_debug(
-                               "%s: Del MAC %s flags 0x%x", __func__,
+                               "%s: Del MAC %s flags %s", __func__,
                                prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
-                               mac->flags);
+                               zebra_evpn_zebra_mac_flag_dump(
+                                       mac, mac_buf, sizeof(mac_buf)));
                }
                wctx->uninstall = 0;
 
@@ -1076,7 +1144,8 @@ static void zebra_evpn_mac_del_hash_entry(struct hash_bucket *bucket, void *arg)
                                        __func__);
 
                        if (mac->flags & ZEBRA_MAC_REMOTE)
-                               zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac);
+                               zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac,
+                                                            false /*force*/);
                }
 
                zebra_evpn_mac_del(wctx->zevpn, mac);
@@ -1181,10 +1250,9 @@ struct hash *zebra_mac_db_create(const char *desc)
 }
 
 /* program sync mac flags in the dataplane  */
-void zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
-                                   bool force_clear_static, const char *caller)
+int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
+                                  bool force_clear_static, const char *caller)
 {
-       char macbuf[ETHER_ADDR_STRLEN];
        struct interface *ifp;
        bool sticky;
        bool set_static;
@@ -1197,29 +1265,35 @@ void zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
        zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
 
        if (!ifp) {
-               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "%s: dp-install sync-mac vni %u mac %s es %s 0x%x %sskipped, no access-port",
-                               caller, zevpn->vni,
-                               prefix_mac2str(&mac->macaddr, macbuf,
-                                              sizeof(macbuf)),
-                               mac->es ? mac->es->esi_str : "-", mac->flags,
+                               "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no access-port",
+                               caller, zevpn->vni, &mac->macaddr,
+                               mac->es ? mac->es->esi_str : "-",
+                               zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                              sizeof(mac_buf)),
                                set_inactive ? "inactive " : "");
-               return;
+               }
+               return -1;
        }
 
        zif = ifp->info;
        br_ifp = zif->brslave_info.br_if;
        if (!br_ifp) {
-               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "%s: dp-install sync-mac vni %u mac %s es %s 0x%x %sskipped, no br",
-                               caller, zevpn->vni,
-                               prefix_mac2str(&mac->macaddr, macbuf,
-                                              sizeof(macbuf)),
-                               mac->es ? mac->es->esi_str : "-", mac->flags,
+                               "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no br",
+                               caller, zevpn->vni, &mac->macaddr,
+                               mac->es ? mac->es->esi_str : "-",
+                               zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                              sizeof(mac_buf)),
                                set_inactive ? "inactive " : "");
-               return;
+               }
+               return -1;
        }
 
        sticky = !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY);
@@ -1228,17 +1302,51 @@ void zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
        else
                set_static = zebra_evpn_mac_is_static(mac);
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
-               zlog_debug(
-                       "dp-install sync-mac vni %u mac %s es %s 0x%x %s%s",
-                       zevpn->vni,
-                       prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
-                       mac->es ? mac->es->esi_str : "-", mac->flags,
-                       set_static ? "static " : "",
-                       set_inactive ? "inactive " : "");
+       /* We can install a local mac that has been synced from the peer
+        * over the VxLAN-overlay/network-port if fast failover is not
+        * supported and if the local ES is oper-down.
+        */
+       if (mac->es && zebra_evpn_es_local_mac_via_network_port(mac->es)) {
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+                       char mac_buf[MAC_BUF_SIZE];
+
+                       zlog_debug(
+                               "dp-%s sync-nw-mac vni %u mac %pEA es %s %s%s",
+                               set_static ? "install" : "uninstall",
+                               zevpn->vni, &mac->macaddr,
+                               mac->es ? mac->es->esi_str : "-",
+                               zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                              sizeof(mac_buf)),
+                               set_inactive ? "inactive " : "");
+               }
+               if (set_static)
+                       /* XXX - old_static needs to be computed more
+                        * accurately
+                        */
+                       zebra_evpn_rem_mac_install(zevpn, mac,
+                                                  true /* old_static */);
+               else
+                       zebra_evpn_rem_mac_uninstall(zevpn, mac,
+                                                    false /* force */);
+
+               return 0;
+       }
+
+       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+               char mac_buf[MAC_BUF_SIZE];
+
+               zlog_debug("dp-install sync-mac vni %u mac %pEA es %s %s%s%s",
+                          zevpn->vni, &mac->macaddr,
+                          mac->es ? mac->es->esi_str : "-",
+                          zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                         sizeof(mac_buf)),
+                          set_static ? "static " : "",
+                          set_inactive ? "inactive " : "");
+       }
 
        dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky,
                             set_static, set_inactive);
+       return 0;
 }
 
 void zebra_evpn_mac_send_add_del_to_client(zebra_mac_t *mac, bool old_bgp_ready,
@@ -1282,12 +1390,17 @@ static int zebra_evpn_mac_hold_exp_cb(struct thread *t)
        new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
        new_static = zebra_evpn_mac_is_static(mac);
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+               char mac_buf[MAC_BUF_SIZE];
+
                zlog_debug(
-                       "sync-mac vni %u mac %s es %s 0x%x hold expired",
+                       "sync-mac vni %u mac %s es %s %shold expired",
                        mac->zevpn->vni,
                        prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
-                       mac->es ? mac->es->esi_str : "-", mac->flags);
+                       mac->es ? mac->es->esi_str : "-",
+                       zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                      sizeof(mac_buf)));
+       }
 
        /* re-program the local mac in the dataplane if the mac is no
         * longer static
@@ -1312,12 +1425,17 @@ static inline void zebra_evpn_mac_start_hold_timer(zebra_mac_t *mac)
        if (mac->hold_timer)
                return;
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+               char mac_buf[MAC_BUF_SIZE];
+
                zlog_debug(
-                       "sync-mac vni %u mac %s es %s 0x%x hold started",
+                       "sync-mac vni %u mac %s es %s %shold started",
                        mac->zevpn->vni,
                        prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
-                       mac->es ? mac->es->esi_str : "-", mac->flags);
+                       mac->es ? mac->es->esi_str : "-",
+                       zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                      sizeof(mac_buf)));
+       }
        thread_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac,
                         zmh_info->mac_hold_time, &mac->hold_timer);
 }
@@ -1329,12 +1447,18 @@ void zebra_evpn_mac_stop_hold_timer(zebra_mac_t *mac)
        if (!mac->hold_timer)
                return;
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+               char mac_buf[MAC_BUF_SIZE];
+
                zlog_debug(
-                       "sync-mac vni %u mac %s es %s 0x%x hold stopped",
+                       "sync-mac vni %u mac %s es %s %shold stopped",
                        mac->zevpn->vni,
                        prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
-                       mac->es ? mac->es->esi_str : "-", mac->flags);
+                       mac->es ? mac->es->esi_str : "-",
+                       zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                      sizeof(mac_buf)));
+       }
+
        THREAD_OFF(mac->hold_timer);
 }
 
@@ -1344,13 +1468,18 @@ void zebra_evpn_sync_mac_del(zebra_mac_t *mac)
        bool old_static;
        bool new_static;
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+               char mac_buf[MAC_BUF_SIZE];
+
                zlog_debug(
-                       "sync-mac del vni %u mac %s es %s seq %d f 0x%x",
+                       "sync-mac del vni %u mac %s es %s seq %d f %s",
                        mac->zevpn->vni,
                        prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
                        mac->es ? mac->es->esi_str : "-", mac->loc_seq,
-                       mac->flags);
+                       zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                      sizeof(mac_buf)));
+       }
+
        old_static = zebra_evpn_mac_is_static(mac);
        UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
        if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
@@ -1367,16 +1496,21 @@ void zebra_evpn_sync_mac_del(zebra_mac_t *mac)
 static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn,
                                                zebra_mac_t *mac, uint32_t seq,
                                                uint16_t ipa_len,
-                                               struct ipaddr *ipaddr)
+                                               struct ipaddr *ipaddr,
+                                               bool sync)
 {
        char macbuf[ETHER_ADDR_STRLEN];
        char ipbuf[INET6_ADDRSTRLEN];
        uint32_t tmp_seq;
+       const char *n_type;
 
-       if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
+       if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
                tmp_seq = mac->loc_seq;
-       else
+               n_type = "local";
+       } else {
                tmp_seq = mac->rem_seq;
+               n_type = "remote";
+       }
 
        if (seq < tmp_seq) {
                /* if the mac was never advertised to bgp we must accept
@@ -1385,31 +1519,44 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn,
                 */
                if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
                    && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) {
-                       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+                       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
+                           || IS_ZEBRA_DEBUG_VXLAN) {
+                               char mac_buf[MAC_BUF_SIZE];
+
                                zlog_debug(
-                                       "sync-macip accept vni %u mac %s%s%s lower seq %u f 0x%x",
-                                       zevpn->vni,
+                                       "%s-macip accept vni %u %s-mac %s%s%s lower seq %u f %s",
+                                       sync ? "sync" : "rem", zevpn->vni,
+                                       n_type,
                                        prefix_mac2str(&mac->macaddr, macbuf,
                                                       sizeof(macbuf)),
                                        ipa_len ? " IP " : "",
                                        ipa_len ? ipaddr2str(ipaddr, ipbuf,
                                                             sizeof(ipbuf))
                                                : "",
-                                       tmp_seq, mac->flags);
+                                       tmp_seq,
+                                       zebra_evpn_zebra_mac_flag_dump(
+                                               mac, mac_buf, sizeof(mac_buf)));
+                       }
+
                        return true;
                }
 
-               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "sync-macip ignore vni %u mac %s%s%s as existing has higher seq %u f 0x%x",
-                               zevpn->vni,
+                               "%s-macip ignore vni %u %s-mac %s%s%s as existing has higher seq %u f %s",
+                               sync ? "sync" : "rem", zevpn->vni, n_type,
                                prefix_mac2str(&mac->macaddr, macbuf,
                                               sizeof(macbuf)),
                                ipa_len ? " IP " : "",
                                ipa_len ? ipaddr2str(ipaddr, ipbuf,
                                                     sizeof(ipbuf))
                                        : "",
-                               tmp_seq, mac->flags);
+                               tmp_seq,
+                               zebra_evpn_zebra_mac_flag_dump(
+                                       mac, mac_buf, sizeof(mac_buf)));
+               }
                return false;
        }
 
@@ -1490,7 +1637,7 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
                        return NULL;
                }
                if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, ipa_len,
-                                                 ipaddr)) {
+                                                 ipaddr, true)) {
                        ctx->ignore_macip = true;
                        return NULL;
                }
@@ -1540,12 +1687,20 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
                memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
                mac->flags = new_flags;
 
-               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags))
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags)) {
+                       char mac_buf[MAC_BUF_SIZE], omac_buf[MAC_BUF_SIZE];
+                       struct zebra_mac_t_ omac;
+
+                       omac.flags = old_flags;
                        zlog_debug(
-                               "sync-mac vni %u mac %s old_f 0x%x new_f 0x%x",
+                               "sync-mac vni %u mac %s old_f %snew_f %s",
                                zevpn->vni,
                                prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
-                               old_flags, mac->flags);
+                               zebra_evpn_zebra_mac_flag_dump(
+                                       &omac, omac_buf, sizeof(omac_buf)),
+                               zebra_evpn_zebra_mac_flag_dump(
+                                       mac, mac_buf, sizeof(mac_buf)));
+               }
 
                /* update es */
                es_change = zebra_evpn_es_mac_ref(mac, esi);
@@ -1579,13 +1734,18 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
                inform_bgp = true;
        }
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
-               zlog_debug("sync-mac %s vni %u mac %s es %s seq %d f 0x%x%s%s",
+       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+               char mac_buf[MAC_BUF_SIZE];
+
+               zlog_debug("sync-mac %s vni %u mac %s es %s seq %d f %s%s%s",
                           ctx->mac_created ? "created" : "updated", zevpn->vni,
                           prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
                           mac->es ? mac->es->esi_str : "-", mac->loc_seq,
-                          mac->flags, inform_bgp ? " inform_bgp" : "",
+                          zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                         sizeof(mac_buf)),
+                          inform_bgp ? "inform_bgp" : "",
                           inform_dataplane ? " inform_dp" : "");
+       }
 
        if (inform_bgp)
                zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
@@ -1694,7 +1854,7 @@ void zebra_evpn_rem_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac)
         * go away, we need to uninstall the MAC.
         */
        if (remote_neigh_count(mac) == 0) {
-               zebra_evpn_rem_mac_uninstall(zevpn, mac);
+               zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/);
                zebra_evpn_es_mac_deref_entry(mac);
                UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
        }
@@ -1740,7 +1900,6 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
 {
        char buf[ETHER_ADDR_STRLEN];
        char buf1[INET6_ADDRSTRLEN];
-       uint32_t tmp_seq;
        bool sticky;
        bool remote_gw;
        int update_mac = 0;
@@ -1800,8 +1959,6 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
                        if (ipa_len)
                                SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
                } else {
-                       zebra_evpn_es_mac_ref(mac, esi);
-
                        /* When host moves but changes its (MAC,IP)
                         * binding, BGP may install a MACIP entry that
                         * corresponds to "older" location of the host
@@ -1810,26 +1967,11 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
                         * the sequence number and ignore this update
                         * if appropriate.
                         */
-                       if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
-                               tmp_seq = mac->loc_seq;
-                       else
-                               tmp_seq = mac->rem_seq;
-
-                       if (seq < tmp_seq) {
-                               if (IS_ZEBRA_DEBUG_VXLAN)
-                                       zlog_debug(
-                                               "Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing MAC has higher seq %u flags 0x%x",
-                                               zevpn->vni,
-                                               prefix_mac2str(macaddr, buf,
-                                                              sizeof(buf)),
-                                               ipa_len ? " IP " : "",
-                                               ipa_len ? ipaddr2str(
-                                                                 ipaddr, buf1,
-                                                                 sizeof(buf1))
-                                                       : "",
-                                               tmp_seq, mac->flags);
+                       if (!zebra_evpn_mac_is_bgp_seq_ok(
+                                   zevpn, mac, seq, ipa_len, ipaddr, false))
                                return -1;
-                       }
+
+                       zebra_evpn_es_mac_ref(mac, esi);
                }
 
                /* Check MAC's curent state is local (this is the case
@@ -1853,14 +1995,20 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
                if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
                        /* force drop the sync flags */
                        old_static = zebra_evpn_mac_is_static(mac);
-                       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+                       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+                               char mac_buf[MAC_BUF_SIZE];
+
                                zlog_debug(
-                                       "sync-mac->remote vni %u mac %s es %s seq %d f 0x%x",
+                                       "sync-mac->remote vni %u mac %s es %s seq %d f %s",
                                        zevpn->vni,
                                        prefix_mac2str(macaddr, buf,
                                                       sizeof(buf)),
                                        mac->es ? mac->es->esi_str : "-",
-                                       mac->loc_seq, mac->flags);
+                                       mac->loc_seq,
+                                       zebra_evpn_zebra_mac_flag_dump(
+                                               mac, mac_buf, sizeof(mac_buf)));
+                       }
+
                        zebra_evpn_mac_clear_sync_info(mac);
                        zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr,
                                                          mac->flags,
@@ -1954,14 +2102,18 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
                        SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
                inform_client = true;
        } else {
-               if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags 0x%x",
+                               "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags %s",
                                sticky ? "sticky " : "",
                                prefix_mac2str(macaddr, buf, sizeof(buf)),
                                ifp->name, ifp->ifindex, vid, zevpn->vni,
                                local_inactive ? "local-inactive " : "",
-                               mac->flags);
+                               zebra_evpn_zebra_mac_flag_dump(
+                                       mac, mac_buf, sizeof(mac_buf)));
+               }
 
                if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
                        struct interface *old_ifp;
@@ -2091,13 +2243,12 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
        }
 
        /* if the dataplane thinks the entry is sync but it is
-        * not sync in zebra we need to re-install to fixup
+        * not sync in zebra (or vice-versa) we need to re-install
+        * to fixup
         */
-       if (dp_static) {
-               new_static = zebra_evpn_mac_is_static(mac);
-               if (!new_static)
-                       inform_dataplane = true;
-       }
+       new_static = zebra_evpn_mac_is_static(mac);
+       if (dp_static != new_static)
+               inform_dataplane = true;
 
        if (local_inactive)
                SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
@@ -2110,14 +2261,19 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
         */
        if ((old_local_inactive != local_inactive)
            || (new_bgp_ready != old_bgp_ready)) {
-               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "local mac vni %u mac %s es %s seq %d f 0x%x%s",
+                               "local mac vni %u mac %s es %s seq %d f %s%s",
                                zevpn->vni,
                                prefix_mac2str(macaddr, buf, sizeof(buf)),
                                mac->es ? mac->es->esi_str : "", mac->loc_seq,
-                               mac->flags,
-                               local_inactive ? " local-inactive" : "");
+                               zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                              sizeof(mac_buf)),
+                               local_inactive ? "local-inactive" : "");
+               }
+
                if (!is_dup_detect)
                        inform_client = true;
        }
@@ -2162,12 +2318,18 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
        if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
                return 0;
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
+       if (IS_ZEBRA_DEBUG_VXLAN) {
+               char mac_buf[MAC_BUF_SIZE];
+
                zlog_debug(
-                       "DEL MAC %s intf %s(%u) VID %u -> VNI %u seq %u flags 0x%x nbr count %u",
+                       "DEL MAC %s intf %s(%u) VID %u -> VNI %u seq %u flags %snbr count %u",
                        prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
                        ifp->ifindex, mac->fwd_info.local.vid, zevpn->vni,
-                       mac->loc_seq, mac->flags, listcount(mac->neigh_list));
+                       mac->loc_seq,
+                       zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                      sizeof(mac_buf)),
+                       listcount(mac->neigh_list));
+       }
 
        old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
        if (zebra_evpn_mac_is_static(mac)) {
@@ -2176,13 +2338,17 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
                 */
                memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
 
-               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "re-add sync-mac vni %u mac %s es %s seq %d f 0x%x",
+                               "re-add sync-mac vni %u mac %s es %s seq %d f %s",
                                zevpn->vni,
                                prefix_mac2str(macaddr, buf, sizeof(buf)),
                                mac->es ? mac->es->esi_str : "-", mac->loc_seq,
-                               mac->flags);
+                               zebra_evpn_zebra_mac_flag_dump(
+                                       mac, mac_buf, sizeof(mac_buf)));
+               }
 
                /* inform-bgp about change in local-activity if any */
                if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
@@ -2193,8 +2359,8 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
                                mac, old_bgp_ready, new_bgp_ready);
                }
 
-               /* re-install the entry in the kernel */
-               zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
+               /* re-install the inactive entry in the kernel */
+               zebra_evpn_sync_mac_dp_install(mac, true /* set_inactive */,
                                               false /* force_clear_static */,
                                               __func__);
 
index 596fd0faad0a723288fe5d39679a212457d50ccc..e21b61050137522988986754aa1939479f189744 100644 (file)
@@ -56,6 +56,7 @@ struct zebra_mac_t_ {
        /* MAC address. */
        struct ethaddr macaddr;
 
+       /* When modifying flags please fixup zebra_evpn_zebra_mac_flag_dump */
        uint32_t flags;
 #define ZEBRA_MAC_LOCAL 0x01
 #define ZEBRA_MAC_REMOTE 0x02
@@ -173,7 +174,6 @@ struct sync_mac_ip_ctx {
        zebra_mac_t *mac;
 };
 
-/**************************** SYNC MAC handling *****************************/
 /**************************** SYNC MAC handling *****************************/
 /* if the mac has been added of a mac-route from the peer
  * or if it is being referenced by a neigh added by the
@@ -204,7 +204,8 @@ static inline void zebra_evpn_mac_clear_sync_info(zebra_mac_t *mac)
 struct hash *zebra_mac_db_create(const char *desc);
 uint32_t num_valid_macs(zebra_evpn_t *zevi);
 uint32_t num_dup_detected_macs(zebra_evpn_t *zevi);
-int zebra_evpn_rem_mac_uninstall(zebra_evpn_t *zevi, zebra_mac_t *mac);
+int zebra_evpn_rem_mac_uninstall(zebra_evpn_t *zevi, zebra_mac_t *mac,
+                                bool force);
 int zebra_evpn_rem_mac_install(zebra_evpn_t *zevi, zebra_mac_t *mac,
                               bool was_static);
 void zebra_evpn_deref_ip2mac(zebra_evpn_t *zevi, zebra_mac_t *mac);
@@ -218,9 +219,8 @@ int zebra_evpn_macip_send_msg_to_client(uint32_t id, struct ethaddr *macaddr,
 void zebra_evpn_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json);
 void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt);
 void zebra_evpn_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt);
-void zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
-                                   bool force_clear_static,
-                                   const char *caller);
+int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
+                                  bool force_clear_static, const char *caller);
 void zebra_evpn_mac_send_add_del_to_client(zebra_mac_t *mac, bool old_bgp_ready,
                                           bool new_bgp_ready);
 
index 692dfca5d7c292a7adbf382e8dded8d21c07dad8..7e712bf1ee9587cc3230f058efd922f95a7833a2 100644 (file)
@@ -57,18 +57,20 @@ DEFINE_MTYPE_STATIC(ZEBRA, ZES, "Ethernet Segment");
 DEFINE_MTYPE_STATIC(ZEBRA, ZES_EVI, "ES info per-EVI");
 DEFINE_MTYPE_STATIC(ZEBRA, ZMH_INFO, "MH global info");
 DEFINE_MTYPE_STATIC(ZEBRA, ZES_VTEP, "VTEP attached to the ES");
+DEFINE_MTYPE_STATIC(ZEBRA, L2_NH, "L2 nexthop");
 
 static void zebra_evpn_es_get_one_base_evpn(void);
 static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
                zebra_evpn_t *zevpn, bool add);
 static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp);
-static int zebra_evpn_local_es_update(struct zebra_if *zif, uint32_t lid,
-               struct ethaddr *sysmac);
+static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi);
 static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
                                                const char *caller);
 static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set);
-static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es);
+static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es,
+                                             bool resync_dplane);
 static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es *es);
+static void zebra_evpn_mh_startup_delay_timer_start(const char *rc);
 
 esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
 
@@ -415,15 +417,12 @@ void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail)
                        vty_out(vty, "Type: L local, R remote\n");
                        vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
                }
+               zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json_array, detail);
        } else {
                if (!uj)
                        vty_out(vty, "VNI %d doesn't exist\n", vni);
-
-               return;
        }
 
-       zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json_array, detail);
-
        if (uj) {
                vty_out(vty, "%s\n",
                        json_object_to_json_string_ext(
@@ -934,7 +933,7 @@ void zebra_evpn_if_init(struct zebra_if *zif)
        /* if an es_id and sysmac are already present against the interface
         * activate it
         */
-       zebra_evpn_local_es_update(zif, zif->es_info.lid, &zif->es_info.sysmac);
+       zebra_evpn_local_es_update(zif, &zif->es_info.esi);
 }
 
 /* handle deletion of an access port by removing it from all associated
@@ -965,30 +964,160 @@ void zebra_evpn_if_cleanup(struct zebra_if *zif)
  *   A L2 NH entry is programmed in the kernel for every ES-VTEP entry. This
  * NH is then added to the L2-ECMP-NHG associated with the ES.
  */
-static uint32_t zebra_evpn_nhid_alloc(bool is_nhg)
+static uint32_t zebra_evpn_nhid_alloc(struct zebra_evpn_es *es)
 {
        uint32_t id;
-       int type;
+       uint32_t nh_id;
 
        bf_assign_index(zmh_info->nh_id_bitmap, id);
 
        if (!id)
                return 0;
 
-       type = is_nhg ? EVPN_NHG_ID_TYPE_BIT : EVPN_NH_ID_TYPE_BIT;
-       return (id | type);
+       if (es) {
+               nh_id = id | EVPN_NHG_ID_TYPE_BIT;
+               /* Add to NHG hash */
+               es->nhg_id = nh_id;
+               if (!hash_get(zmh_info->nhg_table, es, hash_alloc_intern)) {
+                       bf_release_index(zmh_info->nh_id_bitmap, id);
+                       return 0;
+               }
+       } else {
+               nh_id = id | EVPN_NH_ID_TYPE_BIT;
+       }
+
+       return nh_id;
 }
 
-static void zebra_evpn_nhid_free(uint32_t nh_id)
+static void zebra_evpn_nhid_free(uint32_t nh_id, struct zebra_evpn_es *es)
 {
        uint32_t id = (nh_id & EVPN_NH_ID_VAL_MASK);
 
        if (!id)
                return;
 
+       if (es) {
+               hash_release(zmh_info->nhg_table, es);
+               es->nhg_id = 0;
+       }
+
        bf_release_index(zmh_info->nh_id_bitmap, id);
 }
 
+static unsigned int zebra_evpn_nh_ip_hash_keymake(const void *p)
+{
+       const struct zebra_evpn_l2_nh *nh = p;
+
+       return jhash_1word(nh->vtep_ip.s_addr, 0);
+}
+
+static bool zebra_evpn_nh_ip_cmp(const void *p1, const void *p2)
+{
+       const struct zebra_evpn_l2_nh *nh1 = p1;
+       const struct zebra_evpn_l2_nh *nh2 = p2;
+
+       if (nh1 == NULL && nh2 == NULL)
+               return true;
+
+       if (nh1 == NULL || nh2 == NULL)
+               return false;
+
+       return (nh1->vtep_ip.s_addr == nh2->vtep_ip.s_addr);
+}
+
+static unsigned int zebra_evpn_nhg_hash_keymake(const void *p)
+{
+       const struct zebra_evpn_es *es = p;
+
+       return jhash_1word(es->nhg_id, 0);
+}
+
+static bool zebra_evpn_nhg_cmp(const void *p1, const void *p2)
+{
+       const struct zebra_evpn_es *es1 = p1;
+       const struct zebra_evpn_es *es2 = p2;
+
+       if (es1 == NULL && es2 == NULL)
+               return true;
+
+       if (es1 == NULL || es2 == NULL)
+               return false;
+
+       return (es1->nhg_id == es2->nhg_id);
+}
+
+/* Lookup ES using the NHG id associated with it */
+static struct zebra_evpn_es *zebra_evpn_nhg_find(uint32_t nhg_id)
+{
+       struct zebra_evpn_es *es;
+       struct zebra_evpn_es tmp;
+
+       tmp.nhg_id = nhg_id;
+       es = hash_lookup(zmh_info->nhg_table, &tmp);
+
+       return es;
+}
+
+/* Returns TRUE if the NHG is associated with a local ES */
+bool zebra_evpn_nhg_is_local_es(uint32_t nhg_id,
+                               struct zebra_evpn_es **local_es)
+{
+       struct zebra_evpn_es *es;
+
+       es = zebra_evpn_nhg_find(nhg_id);
+       if (es && (es->flags & ZEBRA_EVPNES_LOCAL)) {
+               *local_es = es;
+               return true;
+       }
+
+       *local_es = NULL;
+       return false;
+}
+
+/* update remote macs associated with the ES */
+static void zebra_evpn_nhg_mac_update(struct zebra_evpn_es *es)
+{
+       zebra_mac_t *mac;
+       struct listnode *node;
+       bool local_via_nw;
+
+       local_via_nw = zebra_evpn_es_local_mac_via_network_port(es);
+       if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               zlog_debug("mac update on es %s nhg %s", es->esi_str,
+                          (es->flags & ZEBRA_EVPNES_NHG_ACTIVE)
+                                  ? "activate"
+                                  : "de-activate");
+
+       for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
+               if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
+                   || (local_via_nw && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
+                       && zebra_evpn_mac_is_static(mac))) {
+                       if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
+                               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+                                       zlog_debug(
+                                               "%smac %pEA install via es %s nhg 0x%x",
+                                               (mac->flags & ZEBRA_MAC_REMOTE)
+                                                       ? "rem"
+                                                       : "local-nw",
+                                               &mac->macaddr, es->esi_str,
+                                               es->nhg_id);
+                               zebra_evpn_rem_mac_install(
+                                       mac->zevpn, mac, false /*was_static*/);
+                       } else {
+                               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+                                       zlog_debug(
+                                               "%smac %pEA un-install es %s",
+                                               (mac->flags & ZEBRA_MAC_REMOTE)
+                                                       ? "rem"
+                                                       : "local-nw",
+                                               &mac->macaddr, es->esi_str);
+                               zebra_evpn_rem_mac_uninstall(mac->zevpn, mac,
+                                                            true /*force*/);
+                       }
+               }
+       }
+}
+
 /* The MAC ECMP group is activated on the first VTEP */
 static void zebra_evpn_nhg_update(struct zebra_evpn_es *es)
 {
@@ -1001,14 +1130,14 @@ static void zebra_evpn_nhg_update(struct zebra_evpn_es *es)
                return;
 
        for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
-               if (!es_vtep->nh_id)
+               if (!es_vtep->nh)
                        continue;
 
                if (nh_cnt >= ES_VTEP_MAX_CNT)
                        break;
 
                memset(&nh_ids[nh_cnt], 0, sizeof(struct nh_grp));
-               nh_ids[nh_cnt].id = es_vtep->nh_id;
+               nh_ids[nh_cnt].id = es_vtep->nh->nh_id;
                ++nh_cnt;
        }
 
@@ -1024,11 +1153,10 @@ static void zebra_evpn_nhg_update(struct zebra_evpn_es *es)
                                         nh_ids[i].id);
                                strlcat(nh_str, nh_buf, sizeof(nh_str));
                        }
-                       zlog_debug("es %s nhg 0x%x add %s",
-                                       es->esi_str, es->nhg_id, nh_str);
+                       zlog_debug("es %s nhg %u add %s", es->esi_str,
+                                  es->nhg_id, nh_str);
                }
 
-               es->flags |= ZEBRA_EVPNES_NHG_ACTIVE;
                kernel_upd_mac_nhg(es->nhg_id, nh_cnt, nh_ids);
                if (!(es->flags & ZEBRA_EVPNES_NHG_ACTIVE)) {
                        es->flags |= ZEBRA_EVPNES_NHG_ACTIVE;
@@ -1036,65 +1164,173 @@ static void zebra_evpn_nhg_update(struct zebra_evpn_es *es)
                        if ((es->flags & ZEBRA_EVPNES_LOCAL))
                                zebra_evpn_es_br_port_dplane_update(es,
                                                                    __func__);
+                       zebra_evpn_nhg_mac_update(es);
                }
        } else {
                if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
                        if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
-                               zlog_debug("es %s nhg 0x%x del",
-                                               es->esi_str, es->nhg_id);
+                               zlog_debug("es %s nhg %u del", es->esi_str,
+                                          es->nhg_id);
                        es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
                        /* remove backup NHG from the br-port */
                        if ((es->flags & ZEBRA_EVPNES_LOCAL))
                                zebra_evpn_es_br_port_dplane_update(es,
                                                                    __func__);
+                       zebra_evpn_nhg_mac_update(es);
                        kernel_del_mac_nhg(es->nhg_id);
                }
        }
 
-       /* XXX - update remote macs associated with the ES */
 }
 
-static void zebra_evpn_nh_add(struct zebra_evpn_es_vtep *es_vtep)
+static void zebra_evpn_es_l2_nh_show_entry(struct zebra_evpn_l2_nh *nh,
+                                          struct vty *vty,
+                                          json_object *json_array)
 {
-       if (es_vtep->nh_id)
+       if (json_array) {
+               json_object *json = NULL;
+               char ip_buf[INET6_ADDRSTRLEN];
+
+               json = json_object_new_object();
+               json_object_string_add(json, "vtep",
+                                      inet_ntop(AF_INET, &nh->vtep_ip, ip_buf,
+                                                sizeof(ip_buf)));
+               json_object_int_add(json, "nhId", nh->nh_id);
+               json_object_int_add(json, "refCnt", nh->ref_cnt);
+
+               json_object_array_add(json_array, json);
+       } else {
+               vty_out(vty, "%-16pI4 %-10u %u\n", &nh->vtep_ip, nh->nh_id,
+                       nh->ref_cnt);
+       }
+}
+
+static void zebra_evpn_l2_nh_show_cb(struct hash_bucket *bucket, void *ctxt)
+{
+       struct zebra_evpn_l2_nh *nh = (struct zebra_evpn_l2_nh *)bucket->data;
+       struct evpn_mh_show_ctx *wctx = (struct evpn_mh_show_ctx *)ctxt;
+
+       zebra_evpn_es_l2_nh_show_entry(nh, wctx->vty, wctx->json);
+}
+
+void zebra_evpn_l2_nh_show(struct vty *vty, bool uj)
+{
+       struct evpn_mh_show_ctx wctx;
+       json_object *json_array = NULL;
+
+       if (uj) {
+               json_array = json_object_new_array();
+       } else {
+               vty_out(vty, "%-16s %-10s %s\n", "VTEP", "NH id", "#ES");
+       }
+
+       memset(&wctx, 0, sizeof(wctx));
+       wctx.vty = vty;
+       wctx.json = json_array;
+
+       hash_iterate(zmh_info->nh_ip_table, zebra_evpn_l2_nh_show_cb, &wctx);
+
+       if (uj) {
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json_array, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json_array);
+       }
+}
+
+static struct zebra_evpn_l2_nh *zebra_evpn_l2_nh_find(struct in_addr vtep_ip)
+{
+       struct zebra_evpn_l2_nh *nh;
+       struct zebra_evpn_l2_nh tmp;
+
+       tmp.vtep_ip.s_addr = vtep_ip.s_addr;
+       nh = hash_lookup(zmh_info->nh_ip_table, &tmp);
+
+       return nh;
+}
+
+static struct zebra_evpn_l2_nh *zebra_evpn_l2_nh_alloc(struct in_addr vtep_ip)
+{
+       struct zebra_evpn_l2_nh *nh;
+
+       nh = XCALLOC(MTYPE_L2_NH, sizeof(*nh));
+       nh->vtep_ip = vtep_ip;
+       if (!hash_get(zmh_info->nh_ip_table, nh, hash_alloc_intern)) {
+               XFREE(MTYPE_L2_NH, nh);
+               return NULL;
+       }
+
+       nh->nh_id = zebra_evpn_nhid_alloc(NULL);
+       if (!nh->nh_id) {
+               hash_release(zmh_info->nh_ip_table, nh);
+               XFREE(MTYPE_L2_NH, nh);
+               return NULL;
+       }
+
+       /* install the NH in the dataplane */
+       kernel_upd_mac_nh(nh->nh_id, nh->vtep_ip);
+
+       return nh;
+}
+
+static void zebra_evpn_l2_nh_free(struct zebra_evpn_l2_nh *nh)
+{
+       /* delete the NH from the dataplane */
+       kernel_del_mac_nh(nh->nh_id);
+
+       zebra_evpn_nhid_free(nh->nh_id, NULL);
+       hash_release(zmh_info->nh_ip_table, nh);
+       XFREE(MTYPE_L2_NH, nh);
+}
+
+static void zebra_evpn_l2_nh_es_vtep_ref(struct zebra_evpn_es_vtep *es_vtep)
+{
+       if (es_vtep->nh)
                return;
 
-       es_vtep->nh_id = zebra_evpn_nhid_alloc(false);
+       es_vtep->nh = zebra_evpn_l2_nh_find(es_vtep->vtep_ip);
+       if (!es_vtep->nh)
+               es_vtep->nh = zebra_evpn_l2_nh_alloc(es_vtep->vtep_ip);
 
-       if (!es_vtep->nh_id)
+       if (!es_vtep->nh) {
+               zlog_warn("es %s vtep %pI4 nh ref failed", es_vtep->es->esi_str,
+                         &es_vtep->vtep_ip);
                return;
+       }
+
+       ++es_vtep->nh->ref_cnt;
 
        if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
-               zlog_debug("es %s vtep %pI4 nh 0x%x add",
-                               es_vtep->es->esi_str,
-                               &es_vtep->vtep_ip, es_vtep->nh_id);
-       /* install the NH */
-       kernel_upd_mac_nh(es_vtep->nh_id, es_vtep->vtep_ip);
+               zlog_debug("es %s vtep %pI4 nh %u ref %u", es_vtep->es->esi_str,
+                          &es_vtep->vtep_ip, es_vtep->nh->nh_id,
+                          es_vtep->nh->ref_cnt);
+
        /* add the NH to the parent NHG */
        zebra_evpn_nhg_update(es_vtep->es);
 }
 
-static void zebra_evpn_nh_del(struct zebra_evpn_es_vtep *es_vtep)
+static void zebra_evpn_l2_nh_es_vtep_deref(struct zebra_evpn_es_vtep *es_vtep)
 {
-       uint32_t nh_id;
+       struct zebra_evpn_l2_nh *nh = es_vtep->nh;
 
-       if (!es_vtep->nh_id)
+       if (!nh)
                return;
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
-               zlog_debug("es %s vtep %pI4 nh 0x%x del",
-                               es_vtep->es->esi_str,
-                               &es_vtep->vtep_ip, es_vtep->nh_id);
+       es_vtep->nh = NULL;
+       if (nh->ref_cnt)
+               --nh->ref_cnt;
 
-       nh_id = es_vtep->nh_id;
-       es_vtep->nh_id = 0;
+       if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
+               zlog_debug("es %s vtep %pI4 nh %u deref %u",
+                          es_vtep->es->esi_str, &es_vtep->vtep_ip, nh->nh_id,
+                          nh->ref_cnt);
 
        /* remove the NH from the parent NHG */
        zebra_evpn_nhg_update(es_vtep->es);
-       /* uninstall the NH */
-       kernel_del_mac_nh(nh_id);
-       zebra_evpn_nhid_free(nh_id);
 
+       /* uninstall the NH */
+       if (!nh->ref_cnt)
+               zebra_evpn_l2_nh_free(nh);
 }
 
 /*****************************************************************************/
@@ -1142,7 +1378,7 @@ static void zebra_evpn_es_vtep_free(struct zebra_evpn_es_vtep *es_vtep)
 
        list_delete_node(es->es_vtep_list, &es_vtep->es_listnode);
        /* update the L2-NHG associated with the ES */
-       zebra_evpn_nh_del(es_vtep);
+       zebra_evpn_l2_nh_es_vtep_deref(es_vtep);
        XFREE(MTYPE_ZES_VTEP, es_vtep);
 }
 
@@ -1231,16 +1467,16 @@ static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
 
 /* returns TRUE if dplane entry was updated */
 static bool zebra_evpn_es_df_change(struct zebra_evpn_es *es, bool new_non_df,
-                                   const char *caller)
+                                   const char *caller, const char *reason)
 {
        bool old_non_df;
 
        old_non_df = !!(es->flags & ZEBRA_EVPNES_NON_DF);
 
        if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
-               zlog_debug("df-change(%s) es %s old %s new %s", caller,
-                          es->esi_str, old_non_df ? "non-df" : "df",
-                          new_non_df ? "non-df" : "df");
+               zlog_debug("df-change es %s %s to %s; %s: %s", es->esi_str,
+                          old_non_df ? "non-df" : "df",
+                          new_non_df ? "non-df" : "df", caller, reason);
 
        if (old_non_df == new_non_df)
                return false;
@@ -1268,7 +1504,8 @@ static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
         */
        if (!(es->flags & ZEBRA_EVPNES_LOCAL)
            || !zmh_info->es_originator_ip.s_addr)
-               return zebra_evpn_es_df_change(es, new_non_df, caller);
+               return zebra_evpn_es_df_change(es, new_non_df, caller,
+                                              "not-ready");
 
        /* if oper-state is down DF filtering must be on. when the link comes
         * up again dataplane should block BUM till FRR has had the chance
@@ -1276,7 +1513,18 @@ static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
         */
        if (!(es->flags & ZEBRA_EVPNES_OPER_UP)) {
                new_non_df = true;
-               return zebra_evpn_es_df_change(es, new_non_df, caller);
+               return zebra_evpn_es_df_change(es, new_non_df, caller,
+                                              "oper-down");
+       }
+
+       /* ES was just created; we need to wait for the peers to rx the
+        * our Type-4 routes and for the switch to import the peers' Type-4
+        * routes
+        */
+       if (es->df_delay_timer) {
+               new_non_df = true;
+               return zebra_evpn_es_df_change(es, new_non_df, caller,
+                                              "df-delay");
        }
 
        for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
@@ -1308,7 +1556,7 @@ static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
                }
        }
 
-       return zebra_evpn_es_df_change(es, new_non_df, caller);
+       return zebra_evpn_es_df_change(es, new_non_df, caller, "elected");
 }
 
 static void zebra_evpn_es_vtep_add(struct zebra_evpn_es *es,
@@ -1327,7 +1575,7 @@ static void zebra_evpn_es_vtep_add(struct zebra_evpn_es *es,
                                        es->esi_str, &vtep_ip);
                es_vtep = zebra_evpn_es_vtep_new(es, vtep_ip);
                /* update the L2-NHG associated with the ES */
-               zebra_evpn_nh_add(es_vtep);
+               zebra_evpn_l2_nh_es_vtep_ref(es_vtep);
        }
 
        old_esr_rxed = !!(es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR);
@@ -1398,6 +1646,9 @@ static struct zebra_evpn_es *zebra_evpn_es_new(esi_t *esi)
 {
        struct zebra_evpn_es *es;
 
+       if (!memcmp(esi, zero_esi, sizeof(esi_t)))
+               return NULL;
+
        es = XCALLOC(MTYPE_ZES, sizeof(struct zebra_evpn_es));
 
        /* fill in ESI */
@@ -1424,10 +1675,10 @@ static struct zebra_evpn_es *zebra_evpn_es_new(esi_t *esi)
        listset_app_node_mem(es->mac_list);
 
        /* reserve a NHG  */
-       es->nhg_id = zebra_evpn_nhid_alloc(true);
+       es->nhg_id = zebra_evpn_nhid_alloc(es);
 
        if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
-               zlog_debug("es %s nhg 0x%x new", es->esi_str, es->nhg_id);
+               zlog_debug("es %s nhg %u new", es->esi_str, es->nhg_id);
 
        return es;
 }
@@ -1456,7 +1707,7 @@ static void zebra_evpn_es_free(struct zebra_evpn_es **esp)
                es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
                kernel_del_mac_nhg(es->nhg_id);
        }
-       zebra_evpn_nhid_free(es->nhg_id);
+       zebra_evpn_nhid_free(es->nhg_id, es);
 
        /* cleanup resources maintained against the ES */
        list_delete(&es->es_evi_list);
@@ -1613,6 +1864,8 @@ static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
        uint16_t vid;
        struct zebra_evpn_access_bd *acc_bd;
 
+       if (!bf_is_inited(zif->vlan_bitmap))
+               return;
 
        bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
                acc_bd = zebra_evpn_acc_vl_find(vid);
@@ -1660,6 +1913,67 @@ void zebra_evpn_es_local_br_port_update(struct zebra_if *zif)
                zebra_evpn_es_br_port_dplane_update(es, __func__);
 }
 
+/* On config of first local-ES turn off DAD */
+static void zebra_evpn_mh_dup_addr_detect_off(void)
+{
+       struct zebra_vrf *zvrf;
+       bool old_detect;
+       bool new_detect;
+
+       if (zmh_info->flags & ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF)
+               return;
+
+       zvrf = zebra_vrf_get_evpn();
+       if (!zvrf) {
+               zmh_info->flags |= ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF;
+               return;
+       }
+
+       old_detect = zebra_evpn_do_dup_addr_detect(zvrf);
+       zmh_info->flags |= ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF;
+       new_detect = zebra_evpn_do_dup_addr_detect(zvrf);
+
+       if (old_detect && !new_detect) {
+               if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+                       zlog_debug(
+                               "evpn-mh config caused DAD addr detect chg from %s to %s",
+                               old_detect ? "on" : "off",
+                               new_detect ? "on" : "off");
+               zebra_vxlan_clear_dup_detect_vni_all(zvrf);
+       }
+}
+
+/* On config of first local-ES turn off advertisement of STALE/DELAY/PROBE
+ * neighbors
+ */
+static void zebra_evpn_mh_advertise_reach_neigh_only(void)
+{
+       if (zmh_info->flags & ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY)
+               return;
+
+       zmh_info->flags |= ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY;
+       if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+               zlog_debug("evpn-mh: only REACHABLE neigh advertised");
+
+       /* XXX - if STALE/DELAY/PROBE neighs were previously advertised we
+        * need to withdraw them
+        */
+}
+
+static int zebra_evpn_es_df_delay_exp_cb(struct thread *t)
+{
+       struct zebra_evpn_es *es;
+
+       es = THREAD_ARG(t);
+
+       if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+               zlog_debug("es %s df-delay expired", es->esi_str);
+
+       zebra_evpn_es_run_df_election(es, __func__);
+
+       return 0;
+}
+
 static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
                struct zebra_if *zif)
 {
@@ -1667,8 +1981,11 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
                return;
 
        if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
-               zlog_debug("local es %s add; nhg 0x%x if %s",
-                               es->esi_str, es->nhg_id, zif->ifp->name);
+               zlog_debug("local es %s add; nhg %u if %s", es->esi_str,
+                          es->nhg_id, zif->ifp->name);
+
+       zebra_evpn_mh_dup_addr_detect_off();
+       zebra_evpn_mh_advertise_reach_neigh_only();
 
        es->flags |= ZEBRA_EVPNES_LOCAL;
        listnode_init(&es->local_es_listnode, es);
@@ -1697,6 +2014,12 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
                zebra_evpn_es_re_eval_send_to_client(es,
                        false /* es_evi_re_reval */);
 
+       /* Start the DF delay timer on the local ES */
+       if (!es->df_delay_timer)
+               thread_add_timer(zrouter.master, zebra_evpn_es_df_delay_exp_cb,
+                                es, ZEBRA_EVPN_MH_DF_DELAY_TIME,
+                                &es->df_delay_timer);
+
        /* See if the local VTEP can function as DF on the ES */
        if (!zebra_evpn_es_run_df_election(es, __func__)) {
                /* check if the dplane entry needs to be re-programmed as a
@@ -1719,7 +2042,7 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
                        false /* force_clear_static */);
 
        /* inherit EVPN protodown flags on the access port */
-       zebra_evpn_mh_update_protodown_es(es);
+       zebra_evpn_mh_update_protodown_es(es, true /*resync_dplane*/);
 }
 
 static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
@@ -1733,6 +2056,8 @@ static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
 
        es->flags &= ~(ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_READY_FOR_BGP);
 
+       THREAD_OFF(es->df_delay_timer);
+
        /* remove the DF filter */
        dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
 
@@ -1778,9 +2103,8 @@ static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp)
 
        if (IS_ZEBRA_DEBUG_EVPN_MH_ES) {
                zif = es->zif;
-               zlog_debug("local es %s del; nhg 0x%x if %s",
-                               es->esi_str, es->nhg_id,
-                               zif ? zif->ifp->name : "-");
+               zlog_debug("local es %s del; nhg %u if %s", es->esi_str,
+                          es->nhg_id, zif ? zif->ifp->name : "-");
        }
 
        /* remove all ES-EVIs associated with the ES */
@@ -1804,15 +2128,15 @@ static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es **esp)
                if (!(es->flags & ZEBRA_EVPNES_REMOTE)) {
                        es->flags |= ZEBRA_EVPNES_REMOTE;
                        if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
-                               zlog_debug("remote es %s add; nhg 0x%x",
-                                               es->esi_str, es->nhg_id);
+                               zlog_debug("remote es %s add; nhg %u",
+                                          es->esi_str, es->nhg_id);
                }
        } else {
                if (es->flags & ZEBRA_EVPNES_REMOTE) {
                        es->flags &= ~ZEBRA_EVPNES_REMOTE;
                        if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
-                               zlog_debug("remote es %s del; nhg 0x%x",
-                                               es->esi_str, es->nhg_id);
+                               zlog_debug("remote es %s del; nhg %u",
+                                          es->esi_str, es->nhg_id);
                        zebra_evpn_es_free(esp);
                }
        }
@@ -1821,17 +2145,50 @@ static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es **esp)
 /* A new local es is created when a local-es-id and sysmac is configured
  * against an interface.
  */
-static int zebra_evpn_local_es_update(struct zebra_if *zif, uint32_t lid,
-               struct ethaddr *sysmac)
+static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi)
 {
        struct zebra_evpn_es *old_es = zif->es_info.es;
        struct zebra_evpn_es *es;
+
+       memcpy(&zif->es_info.esi, esi, sizeof(*esi));
+       if (old_es && !memcmp(&old_es->esi, esi, sizeof(*esi)))
+               /* dup - nothing to be done */
+               return 0;
+
+       /* release the old_es against the zif */
+       if (old_es)
+               zebra_evpn_local_es_del(&old_es);
+
+       es = zebra_evpn_es_find(esi);
+       if (es) {
+               /* if it exists against another interface flag an error */
+               if (es->zif && es->zif != zif) {
+                       memset(&zif->es_info.esi, 0, sizeof(*esi));
+                       return -1;
+               }
+       } else {
+               /* create new es */
+               es = zebra_evpn_es_new(esi);
+       }
+
+       if (es)
+               zebra_evpn_es_local_info_set(es, zif);
+
+       return 0;
+}
+
+static int zebra_evpn_type3_esi_update(struct zebra_if *zif, uint32_t lid,
+                                      struct ethaddr *sysmac)
+{
+       struct zebra_evpn_es *old_es = zif->es_info.es;
        esi_t esi;
        int offset = 0;
        int field_bytes = 0;
 
        /* Complete config of the ES-ID bootstraps the ES */
        if (!lid || is_zero_mac(sysmac)) {
+               /* clear old esi */
+               memset(&zif->es_info.esi, 0, sizeof(zif->es_info.esi));
                /* if in ES is attached to zif delete it */
                if (old_es)
                        zebra_evpn_local_es_del(&old_es);
@@ -1853,27 +2210,7 @@ static int zebra_evpn_local_es_update(struct zebra_if *zif, uint32_t lid,
        esi.val[offset++] = (uint8_t)(lid >> 8);
        esi.val[offset++] = (uint8_t)lid;
 
-       if (old_es && !memcmp(&old_es->esi, &esi, sizeof(esi_t)))
-               /* dup - nothing to be done */
-               return 0;
-
-       /* release the old_es against the zif */
-       if (old_es)
-               zebra_evpn_local_es_del(&old_es);
-
-       es = zebra_evpn_es_find(&esi);
-       if (es) {
-               /* if it exists against another interface flag an error */
-               if (es->zif && es->zif != zif)
-                       return -1;
-       } else {
-               /* create new es */
-               es = zebra_evpn_es_new(&esi);
-       }
-
-       zebra_evpn_es_local_info_set(es, zif);
-
-       return 0;
+       return zebra_evpn_local_es_update(zif, &esi);
 }
 
 static int zebra_evpn_remote_es_del(esi_t *esi, struct in_addr vtep_ip)
@@ -2080,7 +2417,7 @@ static int zebra_evpn_es_sys_mac_update(struct zebra_if *zif,
 {
        int rv;
 
-       rv = zebra_evpn_local_es_update(zif, zif->es_info.lid, sysmac);
+       rv = zebra_evpn_type3_esi_update(zif, zif->es_info.lid, sysmac);
        if (!rv)
                memcpy(&zif->es_info.sysmac, sysmac, sizeof(struct ethaddr));
 
@@ -2092,13 +2429,29 @@ static int zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid)
 {
        int rv;
 
-       rv = zebra_evpn_local_es_update(zif, lid, &zif->es_info.sysmac);
+       rv = zebra_evpn_type3_esi_update(zif, lid, &zif->es_info.sysmac);
        if (!rv)
                zif->es_info.lid = lid;
 
        return rv;
 }
 
+/* type-0 esi has changed */
+static int zebra_evpn_es_type0_esi_update(struct zebra_if *zif, esi_t *esi)
+{
+       int rv;
+
+       rv = zebra_evpn_local_es_update(zif, esi);
+
+       /* clear the old es_lid, es_sysmac - type-0 is being set so old
+        * type-3 params need to be flushed
+        */
+       memset(&zif->es_info.sysmac, 0, sizeof(struct ethaddr));
+       zif->es_info.lid = 0;
+
+       return rv;
+}
+
 void zebra_evpn_es_cleanup(void)
 {
        struct zebra_evpn_es *es;
@@ -2156,10 +2509,10 @@ void zebra_evpn_if_es_print(struct vty *vty, struct zebra_if *zif)
        char buf[ETHER_ADDR_STRLEN];
        char mh_buf[80];
        bool vty_print = false;
+       char esi_buf[ESI_STR_LEN];
 
        mh_buf[0] = '\0';
-       snprintf(mh_buf + strlen(mh_buf), sizeof(mh_buf) - strlen(mh_buf),
-                "  EVPN-MH:");
+       strlcat(mh_buf, "  EVPN-MH:", sizeof(mh_buf));
        if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac)) {
                vty_print = true;
                snprintf(
@@ -2167,23 +2520,90 @@ void zebra_evpn_if_es_print(struct vty *vty, struct zebra_if *zif)
                        sizeof(mh_buf) - strlen(mh_buf),
                        " ES id %u ES sysmac %s", zif->es_info.lid,
                        prefix_mac2str(&zif->es_info.sysmac, buf, sizeof(buf)));
+       } else if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi))) {
+               vty_print = true;
+               snprintf(mh_buf + strnlen(mh_buf, sizeof(mh_buf)),
+                        sizeof(mh_buf) - strnlen(mh_buf, sizeof(mh_buf)),
+                        " ES id %s",
+                        esi_to_str(&zif->es_info.esi, esi_buf,
+                                   sizeof(esi_buf)));
        }
 
        if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK) {
                vty_print = true;
                if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)
-                       snprintf(mh_buf + strlen(mh_buf),
-                                sizeof(mh_buf) - strlen(mh_buf), " uplink-up");
+                       strlcat(mh_buf, " uplink (up)", sizeof(mh_buf));
                else
-                       snprintf(mh_buf + strlen(mh_buf),
-                                sizeof(mh_buf) - strlen(mh_buf),
-                                " uplink-down");
+                       strlcat(mh_buf, " uplink (down)", sizeof(mh_buf));
        }
 
        if (vty_print)
                vty_out(vty, "%s\n", mh_buf);
 }
 
+static void zebra_evpn_local_mac_oper_state_change(struct zebra_evpn_es *es)
+{
+       zebra_mac_t *mac;
+       struct listnode *node;
+
+       /* If fast-failover is supported by the dataplane via the use
+        * of an ES backup NHG there is nothing to be done in the
+        * control plane
+        */
+       if (!(zmh_info->flags & ZEBRA_EVPN_MH_REDIRECT_OFF))
+               return;
+
+       if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               zlog_debug("mac slow-fail on es %s %s ", es->esi_str,
+                          (es->flags & ZEBRA_EVPNES_OPER_UP) ? "up" : "down");
+
+       for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
+               if (!(mac->flags & ZEBRA_MAC_LOCAL)
+                   || !zebra_evpn_mac_is_static(mac))
+                       continue;
+
+               if (es->flags & ZEBRA_EVPNES_OPER_UP) {
+                       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+                               zlog_debug(
+                                       "VNI %u mac %pEA move to acc %s es %s %s ",
+                                       mac->zevpn->vni,
+                                       &mac->macaddr,
+                                       es->zif->ifp->name, es->esi_str,
+                                       (es->flags & ZEBRA_EVPNES_OPER_UP)
+                                               ? "up"
+                                               : "down");
+                       /* switch the local macs to access port */
+                       if (zebra_evpn_sync_mac_dp_install(
+                                   mac, false /*set_inactive*/,
+                                   false /*force_clear_static*/, __func__)
+                           < 0)
+                               /* if the local mac install fails get rid of the
+                                * old rem entry
+                                */
+                               zebra_evpn_rem_mac_uninstall(mac->zevpn, mac,
+                                                            true /*force*/);
+               } else {
+                       /* switch the local macs to network port. if there
+                        * is no active NHG we don't bother deleting the MAC;
+                        * that is left up to the dataplane to handle.
+                        */
+                       if (!(es->flags & ZEBRA_EVPNES_NHG_ACTIVE))
+                               continue;
+                       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+                               zlog_debug(
+                                       "VNI %u mac %pEA move to nhg %u es %s %s ",
+                                       mac->zevpn->vni,
+                                       &mac->macaddr,
+                                       es->nhg_id, es->esi_str,
+                                       (es->flags & ZEBRA_EVPNES_OPER_UP)
+                                               ? "up"
+                                               : "down");
+                       zebra_evpn_rem_mac_install(mac->zevpn, mac,
+                                                  true /*was_static*/);
+               }
+       }
+}
+
 void zebra_evpn_es_if_oper_state_change(struct zebra_if *zif, bool up)
 {
        struct zebra_evpn_es *es = zif->es_info.es;
@@ -2202,6 +2622,7 @@ void zebra_evpn_es_if_oper_state_change(struct zebra_if *zif, bool up)
                es->flags &= ~ZEBRA_EVPNES_OPER_UP;
 
        zebra_evpn_es_run_df_election(es, __func__);
+       zebra_evpn_local_mac_oper_state_change(es);
 
        /* inform BGP of the ES oper state change */
        if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
@@ -2257,8 +2678,9 @@ static void zebra_evpn_es_json_vtep_fill(struct zebra_evpn_es *es,
                        json_object_int_add(json_vtep_entry, "dfPreference",
                                            es_vtep->df_pref);
                }
-               json_object_int_add(json_vtep_entry, "nexthopId",
-                                   es_vtep->nh_id);
+               if (es_vtep->nh)
+                       json_object_int_add(json_vtep_entry, "nexthopId",
+                                           es_vtep->nh->nh_id);
                json_object_array_add(json_vteps, json_vtep_entry);
        }
 }
@@ -2325,6 +2747,7 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
        char alg_buf[EVPN_DF_ALG_STR_LEN];
        struct zebra_evpn_es_vtep *es_vtep;
        struct listnode *node;
+       char thread_buf[THREAD_TIMER_STRLEN];
 
        if (json) {
                json_object *json_vteps;
@@ -2361,6 +2784,12 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
                                    listcount(es->es_evi_list));
                json_object_int_add(json, "macCount", listcount(es->mac_list));
                json_object_int_add(json, "dfPreference", es->df_pref);
+               if (es->df_delay_timer)
+                       json_object_string_add(
+                               json, "dfDelayTimer",
+                               thread_timer_to_hhmmss(thread_buf,
+                                                      sizeof(thread_buf),
+                                                      es->df_delay_timer));
                json_object_int_add(json, "nexthopGroup", es->nhg_id);
                if (listcount(es->es_vtep_list)) {
                        json_vteps = json_object_new_array();
@@ -2395,10 +2824,17 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
                                "yes" : "no");
                vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
                vty_out(vty, " MAC Count: %d\n", listcount(es->mac_list));
-               vty_out(vty, " DF: status: %s preference: %u\n",
-                       (es->flags & ZEBRA_EVPNES_NON_DF) ? "non-df" : "df",
-                       es->df_pref);
-               vty_out(vty, " Nexthop group: 0x%x\n", es->nhg_id);
+               if (es->flags & ZEBRA_EVPNES_LOCAL)
+                       vty_out(vty, " DF status: %s \n",
+                               (es->flags & ZEBRA_EVPNES_NON_DF) ? "non-df"
+                                                                 : "df");
+               if (es->df_delay_timer)
+                       vty_out(vty, " DF delay: %s\n",
+                               thread_timer_to_hhmmss(thread_buf,
+                                                      sizeof(thread_buf),
+                                                      es->df_delay_timer));
+               vty_out(vty, " DF preference: %u\n", es->df_pref);
+               vty_out(vty, " Nexthop group: %u\n", es->nhg_id);
                vty_out(vty, " VTEPs:\n");
                for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
                        vty_out(vty, "     %pI4",
@@ -2409,7 +2845,8 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
                                                           alg_buf,
                                                           sizeof(alg_buf)),
                                        es_vtep->df_pref);
-                       vty_out(vty, " nh: 0x%x\n", es_vtep->nh_id);
+                       vty_out(vty, " nh: %u\n",
+                               es_vtep->nh ? es_vtep->nh->nh_id : 0);
                }
 
                vty_out(vty, "\n");
@@ -2498,14 +2935,25 @@ int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp)
 {
        struct zebra_if *zif = ifp->info;
        char buf[ETHER_ADDR_STRLEN];
+       bool type_3_esi = false;
+       char esi_buf[ESI_STR_LEN];
 
-       if (zif->es_info.lid)
+       if (zif->es_info.lid) {
                vty_out(vty, " evpn mh es-id %u\n", zif->es_info.lid);
+               type_3_esi = true;
+       }
 
-       if (!is_zero_mac(&zif->es_info.sysmac))
+       if (!is_zero_mac(&zif->es_info.sysmac)) {
                vty_out(vty, " evpn mh es-sys-mac %s\n",
                                prefix_mac2str(&zif->es_info.sysmac,
                                        buf, sizeof(buf)));
+               type_3_esi = true;
+       }
+
+       if (!type_3_esi
+           && memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi)))
+               vty_out(vty, " evpn mh es-id %s\n",
+                               esi_to_str(&zif->es_info.esi, esi_buf, sizeof(esi_buf)));
 
        if (zif->es_info.df_pref)
                vty_out(vty, " evpn mh es-df-pref %u\n", zif->es_info.df_pref);
@@ -2594,22 +3042,28 @@ DEFPY(zebra_evpn_es_sys_mac,
 /* CLI for setting up local-ID part of ESI on an access port */
 DEFPY(zebra_evpn_es_id,
       zebra_evpn_es_id_cmd,
-      "[no$no] evpn mh es-id [(1-16777215)$es_lid]",
+      "[no$no] evpn mh es-id [(1-16777215)$es_lid | NAME$esi_str]",
       NO_STR
       "EVPN\n"
       EVPN_MH_VTY_STR
-      "Ethernet segment local identifier\n"
-      "ID\n"
+      "Ethernet segment identifier\n"
+      "local discriminator\n"
+      "10-byte ID - 00:AA:BB:CC:DD:EE:FF:GG:HH:II\n"
 )
 {
        VTY_DECLVAR_CONTEXT(interface, ifp);
        struct zebra_if *zif;
-       int ret;
+       int ret = 0;
+       esi_t esi;
 
        zif = ifp->info;
 
        if (no) {
-               ret = zebra_evpn_es_lid_update(zif, 0);
+               if (zif->es_info.lid)
+                       ret = zebra_evpn_es_lid_update(zif, 0);
+               else if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi)))
+                       ret = zebra_evpn_es_type0_esi_update(zif, zero_esi);
+
                if (ret == -1) {
                        vty_out(vty, "%%Failed to clear ES local id\n");
                        return CMD_WARNING;
@@ -2621,14 +3075,23 @@ DEFPY(zebra_evpn_es_id,
                        return CMD_WARNING;
                }
 
-               if  (!es_lid) {
-                       vty_out(vty, "%%Specify local ES ID\n");
-                       return CMD_WARNING;
+               if (esi_str) {
+                       if (!str_to_esi(esi_str, &esi)) {
+                               vty_out(vty, "%% Malformed ESI\n");
+                               return CMD_WARNING;
+                       }
+                       ret = zebra_evpn_es_type0_esi_update(zif, &esi);
+               } else {
+                       if (!es_lid) {
+                               vty_out(vty, "%%Specify local ES ID\n");
+                               return CMD_WARNING;
+                       }
+                       ret = zebra_evpn_es_lid_update(zif, es_lid);
                }
-               ret = zebra_evpn_es_lid_update(zif, es_lid);
+
                if (ret == -1) {
                        vty_out(vty,
-                               "%%ESI already exists on a different interface\n");
+                                       "%%ESI already exists on a different interface\n");
                        return CMD_WARNING;
                }
        }
@@ -2694,7 +3157,7 @@ void zebra_evpn_mh_print(struct vty *vty)
        vty_out(vty, "  uplink-cfg-cnt: %u, uplink-active-cnt: %u\n",
                zmh_info->uplink_cfg_cnt, zmh_info->uplink_oper_up_cnt);
        if (zmh_info->protodown_rc)
-               vty_out(vty, "  protodown: %s\n",
+               vty_out(vty, "  protodown reasons: %s\n",
                        zebra_protodown_rc_str(zmh_info->protodown_rc, pd_buf,
                                               sizeof(pd_buf)));
 }
@@ -2839,16 +3302,14 @@ void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if *zif, bool clear,
                protodown_rc = bond_zif->protodown_rc;
        }
 
-       if (zif->protodown_rc == protodown_rc)
-               return;
-
        old_protodown = !!(zif->flags & ZIF_FLAG_PROTODOWN);
        old_protodown_rc = zif->protodown_rc;
        zif->protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
        zif->protodown_rc |= (protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
        new_protodown = !!zif->protodown_rc;
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+       if (IS_ZEBRA_DEBUG_EVPN_MH_ES
+           && (zif->protodown_rc != old_protodown_rc))
                zlog_debug(
                        "%s bond mbr %s protodown_rc changed; old 0x%x new 0x%x",
                        caller, zif->ifp->name, old_protodown_rc,
@@ -2885,14 +3346,20 @@ static void zebra_evpn_mh_update_protodown_bond(struct zebra_if *bond_zif)
 }
 
 /* The global EVPN MH protodown rc is applied to all local ESs */
-static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es)
+static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es,
+                                             bool resync_dplane)
 {
        struct zebra_if *zif;
        enum protodown_reasons old_protodown_rc;
 
        zif = es->zif;
-       if ((zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL)
-           == (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
+       /* if the reason code is the same bail unless it is a new
+        * ES bond in that case we would need to ensure that the
+        * dplane is really in sync with zebra
+        */
+       if (!resync_dplane
+           && (zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL)
+                      == (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
                return;
 
        old_protodown_rc = zif->protodown_rc;
@@ -2900,7 +3367,8 @@ static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es)
        zif->protodown_rc |=
                (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+       if (IS_ZEBRA_DEBUG_EVPN_MH_ES
+           && (old_protodown_rc != zif->protodown_rc))
                zlog_debug(
                        "es %s ifp %s protodown_rc changed; old 0x%x new 0x%x",
                        es->esi_str, zif->ifp->name, old_protodown_rc,
@@ -2938,7 +3406,7 @@ static void zebra_evpn_mh_update_protodown_es_all(void)
        struct zebra_evpn_es *es;
 
        for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es))
-               zebra_evpn_mh_update_protodown_es(es);
+               zebra_evpn_mh_update_protodown_es(es, false /*resync_dplane*/);
 }
 
 static void zebra_evpn_mh_update_protodown(enum protodown_reasons protodown_rc,
@@ -3046,6 +3514,13 @@ void zebra_evpn_mh_uplink_oper_update(struct zebra_if *zif)
        if (old_protodown == new_protodown)
                return;
 
+       /* if protodown_rc XXX_UPLINK_DOWN is about to be cleared
+        * fire up the start-up delay timer to allow the EVPN network
+        * to converge (Type-2 routes need to be advertised and processed)
+        */
+       if (!new_protodown && (zmh_info->uplink_oper_up_cnt == 1))
+               zebra_evpn_mh_startup_delay_timer_start("uplink-up");
+
        zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN,
                                       new_protodown);
 }
@@ -3061,26 +3536,19 @@ static int zebra_evpn_mh_startup_delay_exp_cb(struct thread *t)
        return 0;
 }
 
-static void zebra_evpn_mh_startup_delay_timer_start(bool init)
+static void zebra_evpn_mh_startup_delay_timer_start(const char *rc)
 {
-       /* 1. This timer can be started during init.
-        * 2. It can also be restarted if it is alreay running and the
-        * admin wants to increase or decrease its value
-        */
-       if (!init && !zmh_info->startup_delay_timer)
-               return;
-
        if (zmh_info->startup_delay_timer) {
                if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
                        zlog_debug("startup-delay timer cancelled");
-               thread_cancel(&zmh_info->startup_delay_timer);
-               zmh_info->startup_delay_timer = NULL;
+               THREAD_OFF(zmh_info->startup_delay_timer);
        }
 
        if (zmh_info->startup_delay_time) {
                if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
-                       zlog_debug("startup-delay timer started for %d sec",
-                                  zmh_info->startup_delay_time);
+                       zlog_debug(
+                               "startup-delay timer started for %d sec on %s",
+                               zmh_info->startup_delay_time, rc);
                thread_add_timer(zrouter.master,
                                 zebra_evpn_mh_startup_delay_exp_cb, NULL,
                                 zmh_info->startup_delay_time,
@@ -3107,6 +3575,9 @@ void zebra_evpn_mh_config_write(struct vty *vty)
        if (zmh_info->startup_delay_time != ZEBRA_EVPN_MH_STARTUP_DELAY_DEF)
                vty_out(vty, "evpn mh startup-delay %d\n",
                        zmh_info->startup_delay_time);
+
+       if (zmh_info->flags & ZEBRA_EVPN_MH_REDIRECT_OFF)
+               vty_out(vty, "evpn mh redirect-off\n");
 }
 
 int zebra_evpn_mh_neigh_holdtime_update(struct vty *vty,
@@ -3138,7 +3609,25 @@ int zebra_evpn_mh_startup_delay_update(struct vty *vty, uint32_t duration,
                duration = ZEBRA_EVPN_MH_STARTUP_DELAY_DEF;
 
        zmh_info->startup_delay_time = duration;
-       zebra_evpn_mh_startup_delay_timer_start(false /* init */);
+
+       /* if startup_delay_timer is running allow it to be adjusted
+        * up or down
+        */
+       if (zmh_info->startup_delay_timer)
+               zebra_evpn_mh_startup_delay_timer_start("config");
+
+       return 0;
+}
+
+int zebra_evpn_mh_redirect_off(struct vty *vty, bool redirect_off)
+{
+       /* This knob needs to be set before ESs are configured
+        * i.e. cannot be changed on the fly
+        */
+       if (redirect_off)
+               zmh_info->flags |= ZEBRA_EVPN_MH_REDIRECT_OFF;
+       else
+               zmh_info->flags &= ~ZEBRA_EVPN_MH_REDIRECT_OFF;
 
        return 0;
 }
@@ -3164,13 +3653,18 @@ void zebra_evpn_mh_init(void)
 
        bf_init(zmh_info->nh_id_bitmap, EVPN_NH_ID_MAX);
        bf_assign_zero_index(zmh_info->nh_id_bitmap);
+       zmh_info->nhg_table = hash_create(zebra_evpn_nhg_hash_keymake,
+                                         zebra_evpn_nhg_cmp, "l2 NHG table");
+       zmh_info->nh_ip_table =
+               hash_create(zebra_evpn_nh_ip_hash_keymake, zebra_evpn_nh_ip_cmp,
+                           "l2 NH IP table");
 
        /* setup broadcast domain tables */
        zmh_info->evpn_vlan_table = hash_create(zebra_evpn_acc_vl_hash_keymake,
                        zebra_evpn_acc_vl_cmp, "access VLAN hash table");
 
        zmh_info->startup_delay_time = ZEBRA_EVPN_MH_STARTUP_DELAY_DEF;
-       zebra_evpn_mh_startup_delay_timer_start(true /*init*/);
+       zebra_evpn_mh_startup_delay_timer_start("init");
 }
 
 void zebra_evpn_mh_terminate(void)
@@ -3180,4 +3674,7 @@ void zebra_evpn_mh_terminate(void)
        hash_iterate(zmh_info->evpn_vlan_table,
                        zebra_evpn_acc_vl_cleanup_all, NULL);
        hash_free(zmh_info->evpn_vlan_table);
+       hash_free(zmh_info->nhg_table);
+       hash_free(zmh_info->nh_ip_table);
+       bf_free(zmh_info->nh_id_bitmap);
 }
index 09af26a3a3d437f82420f238c52172c08db074a8..81ae740d49d5bffb6dd52c872186c3c6c640aa09 100644 (file)
@@ -27,6 +27,7 @@
 #include "bitfield.h"
 #include "zebra_vxlan.h"
 #include "zebra_vxlan_private.h"
+#include "zebra_nhg.h"
 
 #define EVPN_MH_VTY_STR "Multihoming\n"
 
@@ -87,6 +88,13 @@ struct zebra_evpn_es {
         * advertised via the ESR
         */
        uint16_t df_pref;
+
+       /* When a new ES is configured it is held in a non-DF state
+        * for 3 seconds. This allows the peer Type-4 routes to be
+        * imported before running the DF election.
+        */
+#define ZEBRA_EVPN_MH_DF_DELAY_TIME 3 /* seconds */
+       struct thread *df_delay_timer;
 };
 RB_HEAD(zebra_es_rb_head, zebra_evpn_es);
 RB_PROTOTYPE(zebra_es_rb_head, zebra_evpn_es, rb_node, zebra_es_rb_cmp);
@@ -123,6 +131,19 @@ struct zebra_evpn_es_evi {
        struct listnode es_listnode;
 };
 
+/* A single L2 nexthop is allocated across all ESs with the same PE/VTEP
+ * nexthop
+ */
+struct zebra_evpn_l2_nh {
+       struct in_addr vtep_ip;
+
+       /* MAC nexthop id */
+       uint32_t nh_id;
+
+       /* es_vtep entries using this nexthop */
+       uint32_t ref_cnt;
+};
+
 /* PE attached to an ES */
 struct zebra_evpn_es_vtep {
        struct zebra_evpn_es *es; /* parent ES */
@@ -133,12 +154,12 @@ struct zebra_evpn_es_vtep {
 #define ZEBRA_EVPNES_VTEP_RXED_ESR (1 << 0)
 #define ZEBRA_EVPNES_VTEP_DEL_IN_PROG (1 << 1)
 
+       /* MAC nexthop info */
+       struct zebra_evpn_l2_nh *nh;
+
        /* memory used for adding the entry to es->es_vtep_list */
        struct listnode es_listnode;
 
-       /* MAC nexthop */
-       uint32_t nh_id;
-
        /* Parameters for DF election */
        uint8_t df_alg;
        uint32_t df_pref;
@@ -164,6 +185,22 @@ struct zebra_evpn_access_bd {
 /* multihoming information stored in zrouter */
 #define zmh_info (zrouter.mh_info)
 struct zebra_evpn_mh_info {
+       uint32_t flags;
+/* If the dataplane is not capable of handling a backup NHG on an access
+ * port we will need to explicitly failover each MAC entry on
+ * local ES down
+ */
+#define ZEBRA_EVPN_MH_REDIRECT_OFF (1 << 0)
+/* DAD support for EVPN-MH is yet to be added. So on detection of
+ * first local ES, DAD is turned off
+ */
+#define ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF (1 << 1)
+/* If EVPN MH is enabled we only advertise REACHABLE neigh entries as Type-2
+ * routes. As there is no global config knob for enabling EVPN MH we turn
+ * this flag when the first local ES is detected.
+ */
+#define ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY (1 << 2)
+
        /* RB tree of Ethernet segments (used for EVPN-MH)  */
        struct zebra_es_rb_head es_rb_tree;
        /* List of local ESs */
@@ -181,18 +218,21 @@ struct zebra_evpn_mh_info {
        struct in_addr es_originator_ip;
 
        /* L2 NH and NHG ids -
-        * Most significant 8 bits is type. Lower 24 bits is the value
+        * Most significant 4 bits is type. Lower 28 bits is the value
         * allocated from the nh_id_bitmap.
         */
        bitfield_t nh_id_bitmap;
 #define EVPN_NH_ID_MAX       (16*1024)
 #define EVPN_NH_ID_VAL_MASK  0xffffff
-#define EVPN_NH_ID_TYPE_POS  24
 /* The purpose of using different types for NHG and NH is NOT to manage the
  * id space separately. It is simply to make debugging easier.
  */
-#define EVPN_NH_ID_TYPE_BIT  (1 << EVPN_NH_ID_TYPE_POS)
-#define EVPN_NHG_ID_TYPE_BIT (2 << EVPN_NH_ID_TYPE_POS)
+#define EVPN_NH_ID_TYPE_BIT (NHG_TYPE_L2_NH << NHG_ID_TYPE_POS)
+#define EVPN_NHG_ID_TYPE_BIT (NHG_TYPE_L2 << NHG_ID_TYPE_POS)
+       /* L2-NHG table - key: nhg_id, data: zebra_evpn_es */
+       struct hash *nhg_table;
+       /* L2-NH table - key: vtep_up, data: zebra_evpn_nh */
+       struct hash *nh_ip_table;
 
        /* XXX - re-visit the default hold timer value */
        int mac_hold_time;
@@ -228,6 +268,24 @@ static inline bool zebra_evpn_mh_is_fdb_nh(uint32_t id)
                        (id & EVPN_NH_ID_TYPE_BIT));
 }
 
+static inline bool
+zebra_evpn_es_local_mac_via_network_port(struct zebra_evpn_es *es)
+{
+       return !(es->flags & ZEBRA_EVPNES_OPER_UP)
+              && (zmh_info->flags & ZEBRA_EVPN_MH_REDIRECT_OFF);
+}
+
+static inline bool zebra_evpn_mh_do_dup_addr_detect(void)
+{
+       return !(zmh_info->flags & ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF);
+}
+
+static inline bool zebra_evpn_mh_do_adv_reachable_neigh_only(void)
+{
+       return !!(zmh_info->flags & ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY);
+}
+
+
 /*****************************************************************************/
 extern esi_t *zero_esi;
 extern void zebra_evpn_mh_init(void);
@@ -284,5 +342,20 @@ extern bool zebra_evpn_is_es_bond(struct interface *ifp);
 extern bool zebra_evpn_is_es_bond_member(struct interface *ifp);
 extern void zebra_evpn_mh_print(struct vty *vty);
 extern void zebra_evpn_mh_json(json_object *json);
+extern bool zebra_evpn_nhg_is_local_es(uint32_t nhg_id,
+                                      struct zebra_evpn_es **local_es);
+extern int zebra_evpn_mh_redirect_off(struct vty *vty, bool redirect_off);
+extern int zebra_evpn_mh_startup_delay_update(struct vty *vty,
+                                             uint32_t duration,
+                                             bool set_default);
+extern void zebra_evpn_mh_uplink_oper_update(struct zebra_if *zif);
+extern void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if *zif,
+                                                   bool clear,
+                                                   const char *caller);
+extern bool zebra_evpn_is_es_bond(struct interface *ifp);
+extern bool zebra_evpn_is_es_bond_member(struct interface *ifp);
+extern void zebra_evpn_mh_print(struct vty *vty);
+extern void zebra_evpn_mh_json(json_object *json);
+extern void zebra_evpn_l2_nh_show(struct vty *vty, bool uj);
 
 #endif /* _ZEBRA_EVPN_MH_H */
index e4f38008ac8e135411a22bea5491a0389c687abb..1f45b72e3aaba6e950a9aa1f8436103dc32b2195 100644 (file)
@@ -529,16 +529,21 @@ static void zebra_evpn_local_neigh_deref_mac(zebra_neigh_t *n,
 }
 
 bool zebra_evpn_neigh_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_neigh_t *n,
-                                   struct ethaddr *macaddr, uint32_t seq)
+                                   struct ethaddr *macaddr, uint32_t seq,
+                                   bool sync)
 {
        char macbuf[ETHER_ADDR_STRLEN];
        char ipbuf[INET6_ADDRSTRLEN];
        uint32_t tmp_seq;
+       const char *n_type;
 
-       if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
+       if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
                tmp_seq = n->loc_seq;
-       else
+               n_type = "local";
+       } else {
                tmp_seq = n->rem_seq;
+               n_type = "remote";
+       }
 
        if (seq < tmp_seq) {
                /* if the neigh was never advertised to bgp we must accept
@@ -547,10 +552,12 @@ bool zebra_evpn_neigh_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_neigh_t *n,
                 */
                if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)
                    && !zebra_evpn_neigh_is_ready_for_bgp(n)) {
-                       if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+                       if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH
+                           || IS_ZEBRA_DEBUG_VXLAN)
                                zlog_debug(
-                                       "sync-macip accept vni %u mac %s IP %s lower seq %u f 0x%x",
-                                       zevpn->vni,
+                                       "%s-macip accept vni %u %s mac %s IP %s lower seq %u f 0x%x",
+                                       sync ? "sync" : "remote", zevpn->vni,
+                                       n_type,
                                        prefix_mac2str(macaddr, macbuf,
                                                       sizeof(macbuf)),
                                        ipaddr2str(&n->ip, ipbuf,
@@ -559,10 +566,10 @@ bool zebra_evpn_neigh_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_neigh_t *n,
                        return true;
                }
 
-               if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+               if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH || IS_ZEBRA_DEBUG_VXLAN)
                        zlog_debug(
-                               "sync-macip ignore vni %u mac %s IP %s as existing has higher seq %u f 0x%x",
-                               zevpn->vni,
+                               "%s-macip ignore vni %u %s mac %s IP %s as existing has higher seq %u f 0x%x",
+                               sync ? "sync" : "remote", zevpn->vni, n_type,
                                prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
                                ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
                                tmp_seq, n->flags);
@@ -984,7 +991,8 @@ void zebra_evpn_process_neigh_on_local_mac_change(zebra_evpn_t *zevpn,
                            || es_change) {
                                ZEBRA_NEIGH_SET_ACTIVE(n);
                                n->loc_seq = zmac->loc_seq;
-                               if (!(zvrf->dup_addr_detect && zvrf->dad_freeze
+                               if (!(zebra_evpn_do_dup_addr_detect(zvrf)
+                                     && zvrf->dad_freeze
                                      && !!CHECK_FLAG(n->flags,
                                                      ZEBRA_NEIGH_DUPLICATE)))
                                        zebra_evpn_neigh_send_add_to_client(
@@ -1106,7 +1114,7 @@ static int zebra_evpn_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf,
        bool is_old_mac_dup = false;
        bool is_new_mac_dup = false;
 
-       if (!zvrf->dup_addr_detect)
+       if (!zebra_evpn_do_dup_addr_detect(zvrf))
                return 0;
        /* Check old or new MAC is detected as duplicate
         * mark this neigh as duplicate
@@ -1203,7 +1211,7 @@ zebra_evpn_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf, zebra_neigh_t *nbr,
        char buf1[INET6_ADDRSTRLEN];
        bool reset_params = false;
 
-       if (!zvrf->dup_addr_detect)
+       if (!zebra_evpn_do_dup_addr_detect(zvrf))
                return;
 
        /* IP is detected as duplicate or inherit dup
@@ -1452,11 +1460,14 @@ int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp,
                                new_bgp_ready =
                                        zebra_evpn_neigh_is_ready_for_bgp(n);
 
+                               if (dp_static != new_static)
+                                       inform_dataplane = true;
+
                                /* Neigh is in freeze state and freeze action
                                 * is enabled, do not send update to client.
                                 */
                                is_neigh_freezed =
-                                       (zvrf->dup_addr_detect
+                                       (zebra_evpn_do_dup_addr_detect(zvrf)
                                         && zvrf->dad_freeze
                                         && CHECK_FLAG(n->flags,
                                                       ZEBRA_NEIGH_DUPLICATE));
@@ -1466,6 +1477,12 @@ int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp,
                                        old_bgp_ready, new_bgp_ready, false,
                                        false, "flag-update");
 
+                               if (inform_dataplane)
+                                       zebra_evpn_sync_neigh_dp_install(
+                                               n, false /* set_inactive */,
+                                               false /* force_clear_static */,
+                                               __func__);
+
                                /* if the neigh can no longer be advertised
                                 * remove it from bgp
                                 */
@@ -1577,15 +1594,11 @@ int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp,
        else
                UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
 
-       /* if the dataplane thinks that this is a sync entry but
-        * zebra doesn't we need to re-concile the diff
-        * by re-installing the dataplane entry
-        */
-       if (dp_static) {
-               new_static = zebra_evpn_neigh_is_static(n);
-               if (!new_static)
-                       inform_dataplane = true;
-       }
+       /* if zebra and dataplane don't agree this is a sync entry
+        * re-install in the dataplane */
+       new_static = zebra_evpn_neigh_is_static(n);
+       if (dp_static != new_static)
+               inform_dataplane = true;
 
        /* Check old and/or new MAC detected as duplicate mark
         * the neigh as duplicate
@@ -2127,7 +2140,6 @@ void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
 {
        zebra_neigh_t *n;
        int update_neigh = 0;
-       uint32_t tmp_seq;
        char buf[ETHER_ADDR_STRLEN];
        char buf1[INET6_ADDRSTRLEN];
        zebra_mac_t *old_mac = NULL;
@@ -2164,8 +2176,6 @@ void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
                        }
 
                } else {
-                       const char *n_type;
-
                        /* When host moves but changes its (MAC,IP)
                         * binding, BGP may install a MACIP entry that
                         * corresponds to "older" location of the host
@@ -2174,27 +2184,10 @@ void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
                         * the sequence number and ignore this update
                         * if appropriate.
                         */
-                       if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
-                               tmp_seq = n->loc_seq;
-                               n_type = "local";
-                       } else {
-                               tmp_seq = n->rem_seq;
-                               n_type = "remote";
-                       }
-                       if (seq < tmp_seq) {
-                               if (IS_ZEBRA_DEBUG_VXLAN)
-                                       zlog_debug(
-                                               "Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s Neigh has higher seq %u",
-                                               zevpn->vni,
-                                               prefix_mac2str(&mac->macaddr,
-                                                              buf,
-                                                              sizeof(buf)),
-                                               " IP ",
-                                               ipaddr2str(ipaddr, buf1,
-                                                          sizeof(buf1)),
-                                               n_type, tmp_seq);
+
+                       if (!zebra_evpn_neigh_is_bgp_seq_ok(
+                                   zevpn, n, &mac->macaddr, seq, false))
                                return;
-                       }
                        if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
                                old_static = zebra_evpn_neigh_is_static(n);
                                if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
index 50efdc0e0d41b66871eef67e0065035c35808334..eac17a09b4d432676eb86031af6555ff9a84195f 100644 (file)
@@ -237,7 +237,8 @@ int zebra_evpn_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
                                        struct ethaddr *macaddr, uint32_t flags,
                                        int state, bool force);
 bool zebra_evpn_neigh_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_neigh_t *n,
-                                   struct ethaddr *macaddr, uint32_t seq);
+                                   struct ethaddr *macaddr, uint32_t seq,
+                                   bool sync);
 int zebra_evpn_neigh_del(zebra_evpn_t *zevpn, zebra_neigh_t *n);
 void zebra_evpn_sync_neigh_del(zebra_neigh_t *n);
 zebra_neigh_t *
index 2bf48c6277591ed1f9e0bd3cda6aabd1252af001..18ccbb79fba37ab3107e1b36cc2ac610cb60ae85 100644 (file)
@@ -273,6 +273,11 @@ struct zfpm_glob {
         * If non-zero, the last time when statistics were cleared.
         */
        time_t last_stats_clear_time;
+
+       /*
+        * Flag to track the MAC dump status to FPM
+        */
+       bool fpm_mac_dump_done;
 };
 
 static struct zfpm_glob zfpm_glob_space;
@@ -517,8 +522,6 @@ static int zfpm_conn_up_thread_cb(struct thread *thread)
        struct zfpm_rnodes_iter *iter;
        rib_dest_t *dest;
 
-       zfpm_g->t_conn_up = NULL;
-
        iter = &zfpm_g->t_conn_up_state.iter;
 
        if (zfpm_g->state != ZFPM_STATE_ESTABLISHED) {
@@ -528,8 +531,13 @@ static int zfpm_conn_up_thread_cb(struct thread *thread)
                goto done;
        }
 
-       /* Enqueue FPM updates for all the RMAC entries */
-       hash_iterate(zrouter.l3vni_table, zfpm_iterate_rmac_table, NULL);
+       if (!zfpm_g->fpm_mac_dump_done) {
+               /* Enqueue FPM updates for all the RMAC entries */
+               hash_iterate(zrouter.l3vni_table, zfpm_iterate_rmac_table,
+                            NULL);
+               /* mark dump done so that its not repeated after yield */
+               zfpm_g->fpm_mac_dump_done = true;
+       }
 
        while ((rnode = zfpm_rnodes_iter_next(iter))) {
                dest = rib_dest_from_rnode(rnode);
@@ -547,7 +555,6 @@ static int zfpm_conn_up_thread_cb(struct thread *thread)
 
                zfpm_g->stats.t_conn_up_yields++;
                zfpm_rnodes_iter_pause(iter);
-               zfpm_g->t_conn_up = NULL;
                thread_add_timer_msec(zfpm_g->master, zfpm_conn_up_thread_cb,
                                      NULL, 0, &zfpm_g->t_conn_up);
                return 0;
@@ -575,12 +582,13 @@ static void zfpm_connection_up(const char *detail)
        /*
         * Start thread to push existing routes to the FPM.
         */
-       assert(!zfpm_g->t_conn_up);
+       thread_cancel(&zfpm_g->t_conn_up);
 
        zfpm_rnodes_iter_init(&zfpm_g->t_conn_up_state.iter);
+       zfpm_g->fpm_mac_dump_done = false;
 
        zfpm_debug("Starting conn_up thread");
-       zfpm_g->t_conn_up = NULL;
+
        thread_add_timer_msec(zfpm_g->master, zfpm_conn_up_thread_cb, NULL, 0,
                              &zfpm_g->t_conn_up);
        zfpm_g->stats.t_conn_up_starts++;
index 44f574073cb26c2598305d97118bc47ff84529a5..f7c5da5deca067121c17a7eb2ca36c94fc234b0a 100644 (file)
@@ -133,6 +133,7 @@ struct netlink_nh_info {
  * A structure for holding information for a netlink route message.
  */
 struct netlink_route_info {
+       uint32_t nlmsg_pid;
        uint16_t nlmsg_type;
        uint8_t rtm_type;
        uint32_t rtm_table;
@@ -244,14 +245,20 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd,
                                   rib_dest_t *dest, struct route_entry *re)
 {
        struct nexthop *nexthop;
+       struct rib_table_info *table_info =
+               rib_table_info(rib_dest_table(dest));
+       struct zebra_vrf *zvrf = table_info->zvrf;
 
        memset(ri, 0, sizeof(*ri));
 
        ri->prefix = rib_dest_prefix(dest);
        ri->af = rib_dest_af(dest);
 
+       if (zvrf && zvrf->zns)
+               ri->nlmsg_pid = zvrf->zns->netlink_dplane.snl.nl_pid;
+
        ri->nlmsg_type = cmd;
-       ri->rtm_table = rib_table_info(rib_dest_table(dest))->table_id;
+       ri->rtm_table = table_info->table_id;
        ri->rtm_protocol = RTPROT_UNSPEC;
 
        /*
@@ -357,6 +364,7 @@ static int netlink_route_info_encode(struct netlink_route_info *ri,
 
        req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
        req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+       req->n.nlmsg_pid = ri->nlmsg_pid;
        req->n.nlmsg_type = ri->nlmsg_type;
        req->r.rtm_family = ri->af;
 
index da8121774e6e0f0ad6c43ba0dfbeb298498d5cf2..17b52a2bcb0b525dc62f48f173e282cb2e1a84fa 100644 (file)
@@ -30,3 +30,4 @@ DEFINE_MTYPE(ZEBRA, RE, "Route Entry")
 DEFINE_MTYPE(ZEBRA, RIB_DEST, "RIB destination")
 DEFINE_MTYPE(ZEBRA, ZVLAN, "VLAN")
 DEFINE_MTYPE(ZEBRA, ZVLAN_BITMAP, "VLAN bitmap")
+DEFINE_MTYPE(ZEBRA, OPAQUE, "Opaque Data")
index e15f972493269c63906728368a5fceb6c311bf2d..71901b765f7a1fda43d6b56bdaf7e188385bf915 100644 (file)
@@ -32,6 +32,7 @@ DECLARE_MGROUP(ZEBRA)
 DECLARE_MTYPE(ZEBRA_NS)
 DECLARE_MTYPE(RE)
 DECLARE_MTYPE(RIB_DEST)
+DECLARE_MTYPE(OPAQUE)
 
 #ifdef __cplusplus
 }
index 51672330409d02c7407ae1ec5e495b75d1685952..dd2d2e5658ea1e5b2701baf2852305d57f76c358 100644 (file)
@@ -116,6 +116,7 @@ struct zebra_lsp_t_ {
 #define LSP_FLAG_SCHEDULED        (1 << 0)
 #define LSP_FLAG_INSTALLED        (1 << 1)
 #define LSP_FLAG_CHANGED          (1 << 2)
+#define LSP_FLAG_FPM              (1 << 3)
 
        /* Address-family of NHLFE - saved here for delete. All NHLFEs */
        /* have to be of the same AF */
index 3b2279c66c2f1af740d885e5907f36b5eae2fdeb..ce7702b82313d8bd500fb7748371ff34e6963a16 100644 (file)
@@ -28,8 +28,8 @@
 #include "zebra/zebra_mpls.h"
 #include "zebra/kernel_netlink.h"
 
-static ssize_t netlink_lsp_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf,
-                                      size_t buflen)
+ssize_t netlink_lsp_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf,
+                               size_t buflen)
 {
        int cmd;
 
index 196e3c83d0a4ae18398f1a0a1dff3d6f9adce0b1..0a692feb35baa7d0852df70895c21b083e529f74 100644 (file)
@@ -450,12 +450,13 @@ static void *zebra_nhg_hash_alloc(void *arg)
                                         nhe->nhg.nexthop->vrf_id);
                if (ifp)
                        zebra_nhg_set_if(nhe, ifp);
-               else
-                       flog_err(
-                               EC_ZEBRA_IF_LOOKUP_FAILED,
-                               "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
-                               nhe->nhg.nexthop->ifindex,
-                               nhe->nhg.nexthop->vrf_id, nhe->id);
+               else {
+                       if (IS_ZEBRA_DEBUG_NHG)
+                               zlog_debug(
+                                       "Failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
+                                       nhe->nhg.nexthop->ifindex,
+                                       nhe->nhg.nexthop->vrf_id, nhe->id);
+               }
        }
 
        return nhe;
@@ -2119,7 +2120,6 @@ static unsigned nexthop_active_check(struct route_node *rn,
        struct interface *ifp;
        route_map_result_t ret = RMAP_PERMITMATCH;
        int family;
-       char buf[SRCDEST2STR_BUFFER];
        const struct prefix *p, *src_p;
        struct zebra_vrf *zvrf;
 
@@ -2229,10 +2229,9 @@ static unsigned nexthop_active_check(struct route_node *rn,
                                    zvrf, re->tag);
        if (ret == RMAP_DENYMATCH) {
                if (IS_ZEBRA_DEBUG_RIB) {
-                       srcdest_rnode2str(rn, buf, sizeof(buf));
                        zlog_debug(
-                               "%u:%s: Filtering out with NH out %s due to route map",
-                               re->vrf_id, buf,
+                               "%u:%pRN: Filtering out with NH out %s due to route map",
+                               re->vrf_id, rn,
                                ifindex2ifname(nexthop->ifindex,
                                               nexthop->vrf_id));
                }
@@ -2649,10 +2648,11 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
                nhe = zebra_nhg_lookup_id(id);
 
                if (!nhe) {
-                       flog_err(
-                               EC_ZEBRA_NHG_SYNC,
-                               "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
-                               dplane_op2str(op), id);
+                       if (IS_ZEBRA_DEBUG_NHG)
+                               zlog_debug(
+                                       "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
+                                       dplane_op2str(op), id);
+
                        break;
                }
 
index b2ef88bb61a0d4006adcbd96db26685d2fef720d..9382b8c65d11229b53b7f002b7da0251c30a36b4 100644 (file)
@@ -126,6 +126,14 @@ struct nhg_hash_entry {
 #define NEXTHOP_GROUP_FPM (1 << 6)
 };
 
+/* Upper 4 bits of the NHG are reserved for indicating the NHG type */
+#define NHG_ID_TYPE_POS 28
+enum nhg_type {
+       NHG_TYPE_L3 = 0,
+       NHG_TYPE_L2_NH, /* NHs in a L2 NHG used as a MAC/FDB dest */
+       NHG_TYPE_L2,    /* L2 NHG used as a MAC/FDB dest */
+};
+
 /* Was this one we created, either this session or previously? */
 #define ZEBRA_NHG_CREATED(NHE)                                                 \
        (((NHE->type) <= ZEBRA_ROUTE_MAX) && (NHE->type != ZEBRA_ROUTE_KERNEL))
index 569b23573c9297cce90e30a6ab6a9c9fef525702..8914f9c59cff9c1d4c04a630f54319a04330d979 100644 (file)
@@ -38,6 +38,7 @@
 #include "workqueue.h"
 #include "nexthop_group_private.h"
 #include "frr_pthread.h"
+#include "printfrr.h"
 
 #include "zebra/zebra_router.h"
 #include "zebra/connected.h"
@@ -148,6 +149,30 @@ _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn,
        zlog(priority, "%s: (%u:%u):%s: %s", _func, vrf_id, table, buf, msgbuf);
 }
 
+static char *_dump_re_status(const struct route_entry *re, char *buf,
+                            size_t len)
+{
+       if (re->status == 0) {
+               snprintfrr(buf, len, "None ");
+               return buf;
+       }
+
+       snprintfrr(
+               buf, len, "%s%s%s%s%s%s%s",
+               CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED) ? "Removed " : "",
+               CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED) ? "Changed " : "",
+               CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)
+                       ? "Label Changed "
+                       : "",
+               CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED) ? "Queued " : "",
+               CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "Installed "
+                                                             : "",
+               CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED) ? "Failed " : "",
+               CHECK_FLAG(re->status, ROUTE_ENTRY_USE_FIB_NHG) ? "Fib NHG "
+                                                               : "");
+       return buf;
+}
+
 #define rnode_debug(node, vrf_id, ...)                                         \
        _rnode_zlog(__func__, vrf_id, node, LOG_DEBUG, __VA_ARGS__)
 #define rnode_info(node, ...)                                                  \
@@ -250,8 +275,8 @@ done:
        return ret;
 }
 
-void rib_handle_nhg_replace(struct nhg_hash_entry *old,
-                           struct nhg_hash_entry *new)
+void rib_handle_nhg_replace(struct nhg_hash_entry *old_entry,
+                           struct nhg_hash_entry *new_entry)
 {
        struct zebra_router_table *zrt;
        struct route_node *rn;
@@ -259,15 +284,15 @@ void rib_handle_nhg_replace(struct nhg_hash_entry *old,
 
        if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHG_DETAIL)
                zlog_debug("%s: replacing routes nhe (%u) OLD %p NEW %p",
-                          __func__, new->id, new, old);
+                          __func__, new_entry->id, new_entry, old_entry);
 
        /* We have to do them ALL */
        RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) {
                for (rn = route_top(zrt->table); rn;
                     rn = srcdest_route_next(rn)) {
                        RNODE_FOREACH_RE_SAFE (rn, re, next) {
-                               if (re->nhe && re->nhe == old)
-                                       route_entry_update_nhe(re, new);
+                               if (re->nhe && re->nhe == old_entry)
+                                       route_entry_update_nhe(re, new_entry);
                        }
                }
        }
@@ -1080,12 +1105,20 @@ static void rib_process(struct route_node *rn)
        }
 
        RNODE_FOREACH_RE_SAFE (rn, re, next) {
-               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+               if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+                       char flags_buf[128];
+                       char status_buf[128];
+
                        zlog_debug(
-                               "%s(%u:%u):%s: Examine re %p (%s) status %x flags %x dist %d metric %d",
+                               "%s(%u:%u):%s: Examine re %p (%s) status: %sflags: %sdist %d metric %d",
                                VRF_LOGNAME(vrf), vrf_id, re->table, buf, re,
-                               zebra_route_string(re->type), re->status,
-                               re->flags, re->distance, re->metric);
+                               zebra_route_string(re->type),
+                               _dump_re_status(re, status_buf,
+                                               sizeof(status_buf)),
+                               zclient_dump_route_flags(re->flags, flags_buf,
+                                                        sizeof(flags_buf)),
+                               re->distance, re->metric);
+               }
 
                /* Currently selected re. */
                if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
@@ -1107,6 +1140,9 @@ static void rib_process(struct route_node *rn)
                 */
                if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
                        if (!nexthop_active_update(rn, re)) {
+                               const struct prefix *p;
+                               struct rib_table_info *info;
+
                                if (re->type == ZEBRA_ROUTE_TABLE) {
                                        /* XXX: HERE BE DRAGONS!!!!!
                                         * In all honesty, I have not yet
@@ -1136,6 +1172,11 @@ static void rib_process(struct route_node *rn)
                                                         ROUTE_ENTRY_REMOVED);
                                }
 
+                               info = srcdest_rnode_table_info(rn);
+                               srcdest_rnode_prefixes(rn, &p, NULL);
+                               zsend_route_notify_owner(re, p,
+                                                        ZAPI_ROUTE_FAIL_INSTALL,
+                                                        info->afi, info->safi);
                                continue;
                        }
                } else {
@@ -2665,6 +2706,8 @@ void rib_unlink(struct route_node *rn, struct route_entry *re)
 
        nexthops_free(re->fib_ng.nexthop);
 
+       XFREE(MTYPE_OPAQUE, re->opaque);
+
        XFREE(MTYPE_RE, re);
 }
 
@@ -2748,7 +2791,7 @@ static void _route_entry_dump_nh(const struct route_entry *re,
        if (nexthop->weight)
                snprintf(wgt_str, sizeof(wgt_str), "wgt %d,", nexthop->weight);
 
-       zlog_debug("%s: %s %s[%u] vrf %s(%u) %s%s with flags %s%s%s%s%s",
+       zlog_debug("%s: %s %s[%u] vrf %s(%u) %s%s with flags %s%s%s%s%s%s%s%s",
                   straddr, (nexthop->rparent ? "  NH" : "NH"), nhname,
                   nexthop->ifindex, vrf ? vrf->name : "Unknown",
                   nexthop->vrf_id,
@@ -2767,7 +2810,13 @@ static void _route_entry_dump_nh(const struct route_entry *re,
                    : ""),
                   (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)
                    ? "DUPLICATE "
-                   : ""));
+                   : ""),
+                  (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RNH_FILTERED)
+                   ? "FILTERED " : ""),
+                  (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)
+                   ? "BACKUP " : ""),
+                  (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_SRTE)
+                   ? "SRTE " : ""));
 
 }
 
@@ -2783,6 +2832,8 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
        bool is_srcdst = src_p && src_p->prefixlen;
        char straddr[PREFIX_STRLEN];
        char srcaddr[PREFIX_STRLEN];
+       char flags_buf[128];
+       char status_buf[128];
        struct nexthop *nexthop;
        struct vrf *vrf = vrf_lookup_by_id(re->vrf_id);
        struct nexthop_group *nhg;
@@ -2796,9 +2847,12 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
        zlog_debug("%s: uptime == %lu, type == %u, instance == %d, table == %d",
                   straddr, (unsigned long)re->uptime, re->type, re->instance,
                   re->table);
-       zlog_debug("%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u",
-                  straddr, re->metric, re->mtu, re->distance, re->flags,
-                  re->status);
+       zlog_debug(
+               "%s: metric == %u, mtu == %u, distance == %u, flags == %sstatus == %s",
+               straddr, re->metric, re->mtu, re->distance,
+               zclient_dump_route_flags(re->flags, flags_buf,
+                                        sizeof(flags_buf)),
+               _dump_re_status(re, status_buf, sizeof(status_buf)));
        zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr,
                   nexthop_group_nexthop_num(&(re->nhe->nhg)),
                   nexthop_group_active_nexthop_num(&(re->nhe->nhg)));
@@ -2933,8 +2987,10 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
        struct nhg_hash_entry *nhe = NULL;
        struct route_table *table;
        struct route_node *rn;
-       struct route_entry *same = NULL;
+       struct route_entry *same = NULL, *first_same = NULL;
        int ret = 0;
+       int same_count = 0;
+       rib_dest_t *dest;
 
        if (!re || !re_nhe)
                return -1;
@@ -3002,14 +3058,22 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
         * for the install don't do a route replace.
         */
        RNODE_FOREACH_RE (rn, same) {
-               if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED))
+               if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED)) {
+                       same_count++;
                        continue;
+               }
 
                /* Compare various route_entry properties */
-               if (rib_compare_routes(re, same))
-                       break;
+               if (rib_compare_routes(re, same)) {
+                       same_count++;
+
+                       if (first_same == NULL)
+                               first_same = same;
+               }
        }
 
+       same = first_same;
+
        /* If this route is kernel/connected route, notify the dataplane. */
        if (RIB_SYSTEM_ROUTE(re)) {
                /* Notify dataplane */
@@ -3019,8 +3083,9 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
        /* Link new re to node.*/
        if (IS_ZEBRA_DEBUG_RIB) {
                rnode_debug(rn, re->vrf_id,
-                           "Inserting route rn %p, re %p (%s) existing %p",
-                           rn, re, zebra_route_string(re->type), same);
+                           "Inserting route rn %p, re %p (%s) existing %p, same_count %d",
+                           rn, re, zebra_route_string(re->type), same,
+                           same_count);
 
                if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                        route_entry_dump(p, src_p, re);
@@ -3034,6 +3099,24 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
        if (same)
                rib_delnode(rn, same);
 
+       /* See if we can remove some RE entries that are queued for
+        * removal, but won't be considered in rib processing.
+        */
+       dest = rib_dest_from_rnode(rn);
+       RNODE_FOREACH_RE_SAFE (rn, re, same) {
+               if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) {
+                       /* If the route was used earlier, must retain it. */
+                       if (dest && re == dest->selected_fib)
+                               continue;
+
+                       if (IS_ZEBRA_DEBUG_RIB)
+                               rnode_debug(rn, re->vrf_id, "rn %p, removing unneeded re %p",
+                                           rn, re);
+
+                       rib_unlink(rn, re);
+               }
+       }
+
        route_unlock_node(rn);
        return ret;
 }
@@ -3080,7 +3163,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
                unsigned short instance, uint32_t flags, struct prefix *p,
                struct prefix_ipv6 *src_p, const struct nexthop *nh,
                uint32_t nhe_id, uint32_t table_id, uint32_t metric,
-               uint8_t distance, bool fromkernel, bool connected_down)
+               uint8_t distance, bool fromkernel)
 {
        struct route_table *table;
        struct route_node *rn;
@@ -3286,19 +3369,6 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
                rib_delnode(rn, same);
        }
 
-       /*
-        * This is to force an immediate re-eval of this particular
-        * node via nexthop tracking.  Why?  Because there are scenarios
-        * where the interface is flapping and the normal queuing methodology
-        * will cause down/up events to very very rarely be combined into
-        * a non-event from nexthop tracking perspective.  Leading
-        * to some fun timing situations with upper level routing protocol
-        * trying to and failing to install routes during this blip.  Especially
-        * when zebra is under load.
-        */
-       if (connected_down)
-               zebra_rib_evaluate_rn_nexthops(rn,
-                                              zebra_router_get_next_sequence());
        route_unlock_node(rn);
        return;
 }
@@ -3383,7 +3453,8 @@ static void rib_update_route_node(struct route_node *rn, int type)
 }
 
 /* Schedule routes of a particular table (address-family) based on event. */
-void rib_update_table(struct route_table *table, enum rib_update_event event)
+void rib_update_table(struct route_table *table, enum rib_update_event event,
+                     int rtype)
 {
        struct route_node *rn;
 
@@ -3396,12 +3467,12 @@ void rib_update_table(struct route_table *table, enum rib_update_event event)
                               : NULL;
                vrf = zvrf ? zvrf->vrf : NULL;
 
-               zlog_debug("%s: %s VRF %s Table %u event %s", __func__,
+               zlog_debug("%s: %s VRF %s Table %u event %s Route type: %s", __func__,
                           table->info ? afi2str(
                                   ((struct rib_table_info *)table->info)->afi)
                                       : "Unknown",
                           VRF_LOGNAME(vrf), zvrf ? zvrf->table_id : 0,
-                          rib_update_event2str(event));
+                          rib_update_event2str(event), zebra_route_string(rtype));
        }
 
        /* Walk all routes and queue for processing, if appropriate for
@@ -3424,7 +3495,7 @@ void rib_update_table(struct route_table *table, enum rib_update_event event)
                        break;
                case RIB_UPDATE_RMAP_CHANGE:
                case RIB_UPDATE_OTHER:
-                       rib_update_route_node(rn, ZEBRA_ROUTE_ALL);
+                       rib_update_route_node(rn, rtype);
                        break;
                default:
                        break;
@@ -3432,7 +3503,8 @@ void rib_update_table(struct route_table *table, enum rib_update_event event)
        }
 }
 
-static void rib_update_handle_vrf(vrf_id_t vrf_id, enum rib_update_event event)
+static void rib_update_handle_vrf(vrf_id_t vrf_id, enum rib_update_event event,
+                                 int rtype)
 {
        struct route_table *table;
 
@@ -3443,14 +3515,14 @@ static void rib_update_handle_vrf(vrf_id_t vrf_id, enum rib_update_event event)
        /* Process routes of interested address-families. */
        table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id);
        if (table)
-               rib_update_table(table, event);
+               rib_update_table(table, event, rtype);
 
        table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, vrf_id);
        if (table)
-               rib_update_table(table, event);
+               rib_update_table(table, event, rtype);
 }
 
-static void rib_update_handle_vrf_all(enum rib_update_event event)
+static void rib_update_handle_vrf_all(enum rib_update_event event, int rtype)
 {
        struct zebra_router_table *zrt;
 
@@ -3460,7 +3532,7 @@ static void rib_update_handle_vrf_all(enum rib_update_event event)
 
        /* Just iterate over all the route tables, rather than vrf lookups */
        RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables)
-               rib_update_table(zrt->table, event);
+               rib_update_table(zrt->table, event, rtype);
 }
 
 struct rib_update_ctx {
@@ -3494,9 +3566,9 @@ static int rib_update_handler(struct thread *thread)
        ctx = THREAD_ARG(thread);
 
        if (ctx->vrf_all)
-               rib_update_handle_vrf_all(ctx->event);
+               rib_update_handle_vrf_all(ctx->event, ZEBRA_ROUTE_ALL);
        else
-               rib_update_handle_vrf(ctx->vrf_id, ctx->event);
+               rib_update_handle_vrf(ctx->vrf_id, ctx->event, ZEBRA_ROUTE_ALL);
 
        rib_update_ctx_fini(&ctx);
 
@@ -3509,26 +3581,6 @@ static int rib_update_handler(struct thread *thread)
  */
 static struct thread *t_rib_update_threads[RIB_UPDATE_MAX];
 
-/* Schedule a RIB update event for specific vrf */
-void rib_update_vrf(vrf_id_t vrf_id, enum rib_update_event event)
-{
-       struct rib_update_ctx *ctx;
-
-       ctx = rib_update_ctx_init(vrf_id, event);
-
-       /* Don't worry about making sure multiple rib updates for specific vrf
-        * are scheduled at once for now. If it becomes a problem, we can use a
-        * lookup of some sort to keep track of running threads via t_vrf_id
-        * like how we are doing it in t_rib_update_threads[].
-        */
-       thread_add_event(zrouter.master, rib_update_handler, ctx, 0, NULL);
-
-       if (IS_ZEBRA_DEBUG_EVENT)
-               zlog_debug("%s: Scheduled VRF %s, event %s", __func__,
-                          vrf_id_to_name(ctx->vrf_id),
-                          rib_update_event2str(event));
-}
-
 /* Schedule a RIB update event for all vrfs */
 void rib_update(enum rib_update_event event)
 {
@@ -3728,6 +3780,7 @@ static int handle_pw_result(struct zebra_dplane_ctx *ctx)
        }
 
 done:
+       dplane_ctx_fini(&ctx);
 
        return 0;
 }
index 521f969fcc44ac3518900196e65bc5baa407bd5f..3c4dbc5e9cff9ca6c473e7b25195f9daca7ba959 100644 (file)
@@ -152,7 +152,7 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, enum rnh_type type,
                flog_warn(EC_ZEBRA_RNH_NO_TABLE,
                          "%s(%u): Add RNH %pFX type %s - table not found",
                          VRF_LOGNAME(vrf), vrfid, p, rnh_type2str(type));
-               exists = false;
+               *exists = false;
                return NULL;
        }
 
index 7b0a1e3d9c59c76245160f553141f7415be67029..229b705ec948f2c7e6e16f9adf1ee5868a5568e8 100644 (file)
@@ -267,7 +267,8 @@ static int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap,
                /* Process routes of interested address-families. */
                table = zebra_vrf_table(afi, safi, zvrf->vrf->vrf_id);
                if (table)
-                       rib_update_table(table, RIB_UPDATE_RMAP_CHANGE);
+                       rib_update_table(table, RIB_UPDATE_RMAP_CHANGE,
+                                        rtype);
        }
 
        return CMD_SUCCESS;
@@ -294,7 +295,8 @@ static int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap,
                        /* Process routes of interested address-families. */
                        table = zebra_vrf_table(afi, safi, zvrf->vrf->vrf_id);
                        if (table)
-                               rib_update_table(table, RIB_UPDATE_RMAP_CHANGE);
+                               rib_update_table(table, RIB_UPDATE_RMAP_CHANGE,
+                                                rtype);
                }
                XFREE(MTYPE_ROUTE_MAP_NAME, PROTO_RM_NAME(zvrf, afi, rtype));
        }
@@ -576,7 +578,7 @@ DEFUN (zebra_route_map_timer,
        ZEBRA_STR
        "Set route-map parameters\n"
        "Time to wait before route-map updates are processed\n"
-       "0 means event-driven updates are disabled\n")
+       "0 means route-map changes are run immediately instead of delaying\n")
 {
        int idx_number = 3;
        uint32_t rmap_delay_timer;
@@ -594,7 +596,7 @@ DEFUN (no_zebra_route_map_timer,
        ZEBRA_STR
        "Set route-map parameters\n"
        "Reset delay-timer to default value, 30 secs\n"
-       "0 means event-driven updates are disabled\n")
+       "0 means route-map changes are run immediately instead of delaying\n")
 {
        zebra_route_map_set_delay_timer(ZEBRA_RMAP_DEFAULT_UPDATE_TIMER);
 
@@ -1454,8 +1456,6 @@ static void zebra_rib_table_rm_update(const char *rmap)
        struct vrf *vrf = NULL;
        struct zebra_vrf *zvrf = NULL;
        char *rmap_name;
-       char afi_ip = 0;
-       char afi_ipv6 = 0;
        struct route_map *old = NULL;
 
        RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
@@ -1486,16 +1486,12 @@ static void zebra_rib_table_rm_update(const char *rmap)
                                                PROTO_RM_MAP(zvrf, AFI_IP, i));
                                /* There is single rib table for all protocols
                                 */
-                               if (afi_ip == 0) {
-                                       table = zvrf->table[AFI_IP]
-                                                          [SAFI_UNICAST];
-                                       if (table) {
-
-                                               afi_ip = 1;
-                                               rib_update_table(
-                                                       table,
-                                                       RIB_UPDATE_RMAP_CHANGE);
-                                       }
+                               table = zvrf->table[AFI_IP][SAFI_UNICAST];
+                               if (table) {
+                                       rib_update_table(
+                                               table,
+                                               RIB_UPDATE_RMAP_CHANGE,
+                                               i);
                                }
                        }
                        rmap_name = PROTO_RM_NAME(zvrf, AFI_IP6, i);
@@ -1515,16 +1511,12 @@ static void zebra_rib_table_rm_update(const char *rmap)
                                                PROTO_RM_MAP(zvrf, AFI_IP6, i));
                                /* There is single rib table for all protocols
                                 */
-                               if (afi_ipv6 == 0) {
-                                       table = zvrf->table[AFI_IP6]
-                                                          [SAFI_UNICAST];
-                                       if (table) {
-
-                                               afi_ipv6 = 1;
-                                               rib_update_table(
-                                                       table,
-                                                       RIB_UPDATE_RMAP_CHANGE);
-                                       }
+                               table = zvrf->table[AFI_IP6][SAFI_UNICAST];
+                               if (table) {
+                                       rib_update_table(
+                                               table,
+                                               RIB_UPDATE_RMAP_CHANGE,
+                                               i);
                                }
                        }
                }
@@ -1628,8 +1620,6 @@ static void zebra_route_map_process_update_cb(char *rmap_name)
 
 static int zebra_route_map_update_timer(struct thread *thread)
 {
-       zebra_t_rmap_update = NULL;
-
        if (IS_ZEBRA_DEBUG_EVENT)
                zlog_debug("Event driven route-map update triggered");
 
@@ -1654,8 +1644,8 @@ static void zebra_route_map_set_delay_timer(uint32_t value)
        if (!value && zebra_t_rmap_update) {
                /* Event driven route map updates is being disabled */
                /* But there's a pending timer. Fire it off now */
-               thread_cancel(&zebra_t_rmap_update);
-               zebra_route_map_update_timer(zebra_t_rmap_update);
+               THREAD_OFF(zebra_t_rmap_update);
+               zebra_route_map_update_timer(NULL);
        }
 }
 
@@ -1664,24 +1654,17 @@ void zebra_routemap_finish(void)
        /* Set zebra_rmap_update_timer to 0 so that it wont schedule again */
        zebra_rmap_update_timer = 0;
        /* Thread off if any scheduled already */
-       thread_cancel(&zebra_t_rmap_update);
+       THREAD_OFF(zebra_t_rmap_update);
        route_map_finish();
 }
 
-void zebra_route_map_write_delay_timer(struct vty *vty)
-{
-       if (vty && (zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER))
-               vty_out(vty, "zebra route-map delay-timer %d\n",
-                       zebra_rmap_update_timer);
-       return;
-}
-
 route_map_result_t
 zebra_route_map_check(int family, int rib_type, uint8_t instance,
                      const struct prefix *p, struct nexthop *nexthop,
                      struct zebra_vrf *zvrf, route_tag_t tag)
 {
        struct route_map *rmap = NULL;
+       char *rm_name;
        route_map_result_t ret = RMAP_PERMITMATCH;
        struct nh_rmap_obj nh_obj;
 
@@ -1692,10 +1675,20 @@ zebra_route_map_check(int family, int rib_type, uint8_t instance,
        nh_obj.metric = 0;
        nh_obj.tag = tag;
 
-       if (rib_type >= 0 && rib_type < ZEBRA_ROUTE_MAX)
+       if (rib_type >= 0 && rib_type < ZEBRA_ROUTE_MAX) {
+               rm_name = PROTO_RM_NAME(zvrf, family, rib_type);
                rmap = PROTO_RM_MAP(zvrf, family, rib_type);
-       if (!rmap && PROTO_RM_NAME(zvrf, family, ZEBRA_ROUTE_MAX))
+
+               if (rm_name && !rmap)
+                       return RMAP_DENYMATCH;
+       }
+       if (!rmap) {
+               rm_name = PROTO_RM_NAME(zvrf, family, ZEBRA_ROUTE_MAX);
                rmap = PROTO_RM_MAP(zvrf, family, ZEBRA_ROUTE_MAX);
+
+               if (rm_name && !rmap)
+                       return RMAP_DENYMATCH;
+       }
        if (rmap) {
                ret = route_map_apply(rmap, p, &nh_obj);
        }
@@ -1777,12 +1770,11 @@ route_map_result_t zebra_nht_route_map_check(afi_t afi, int client_proto,
 static void zebra_route_map_mark_update(const char *rmap_name)
 {
        /* rmap_update_timer of 0 means don't do route updates */
-       if (zebra_rmap_update_timer && !zebra_t_rmap_update) {
-               zebra_t_rmap_update = NULL;
-               thread_add_timer(zrouter.master, zebra_route_map_update_timer,
-                                NULL, zebra_rmap_update_timer,
-                                &zebra_t_rmap_update);
-       }
+       if (zebra_rmap_update_timer)
+               THREAD_OFF(zebra_t_rmap_update);
+
+       thread_add_timer(zrouter.master, zebra_route_map_update_timer,
+                        NULL, zebra_rmap_update_timer, &zebra_t_rmap_update);
 }
 
 static void zebra_route_map_add(const char *rmap_name)
@@ -1859,7 +1851,8 @@ void zebra_routemap_config_write_protocol(struct vty *vty,
                vty_out(vty, "%sipv6 nht %s route-map %s\n", space, "any",
                        NHT_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX));
 
-       if (zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER)
+       if (zvrf_id(zvrf) == VRF_DEFAULT
+           && zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER)
                vty_out(vty, "zebra route-map delay-timer %d\n",
                        zebra_rmap_update_timer);
 }
index 56e805ea03315c48133674a2e379ba49ed28a097..251e07af722cb5a9be845f680b89127cbacb85b0 100644 (file)
@@ -36,8 +36,6 @@ extern void zebra_add_import_table_route_map(afi_t afi, const char *rmap_name,
                                             uint32_t table);
 extern void zebra_del_import_table_route_map(afi_t afi, uint32_t table);
 
-extern void zebra_route_map_write_delay_timer(struct vty *);
-
 extern route_map_result_t
 zebra_import_table_route_map_check(int family, int rib_type, uint8_t instance,
                                   const struct prefix *p,
index b7cbf5262a832e3e1125a78dfccb1ce0a1b992b3..be4fb29aae88d208dfe84c2fabe1c42628cbd801 100644 (file)
@@ -107,6 +107,8 @@ static int zebra_vrf_new(struct vrf *vrf)
        zvrf = zebra_vrf_alloc();
        vrf->info = zvrf;
        zvrf->vrf = vrf;
+       if (!vrf_is_backend_netns())
+               zvrf->zns = zebra_ns_lookup(NS_DEFAULT);
 
        otable_init(&zvrf->other_tables);
 
index ea7baa2565d9c6ec1e55b7e5bc4a96bb6d523f0a..f18d8fbb6d9151fc2af304eb14be4201d357b8d4 100644 (file)
@@ -419,6 +419,33 @@ static void show_nexthop_detail_helper(struct vty *vty,
        }
 }
 
+static void zebra_show_ip_route_opaque(struct vty *vty, struct route_entry *re,
+                                      struct json_object *json)
+{
+       if (!re->opaque)
+               return;
+
+       switch (re->type) {
+       case ZEBRA_ROUTE_SHARP:
+               if (json)
+                       json_object_string_add(json, "opaque",
+                                              (char *)re->opaque->data);
+               else
+                       vty_out(vty, "    Opaque Data: %s",
+                               (char *)re->opaque->data);
+               break;
+       case ZEBRA_ROUTE_BGP:
+               if (json)
+                       json_object_string_add(json, "asPath",
+                                              (char *)re->opaque->data);
+               else
+                       vty_out(vty, "    AS-Path: %s",
+                               (char *)re->opaque->data);
+       default:
+               break;
+       }
+}
+
 /* New RIB.  Detailed information for IPv4 route. */
 static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
                                     int mcast, bool use_fib, bool show_ng)
@@ -495,6 +522,8 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
                        if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
                                show_nh_backup_helper(vty, re, nexthop);
                }
+               zebra_show_ip_route_opaque(vty, re, NULL);
+
                vty_out(vty, "\n");
        }
 }
@@ -927,6 +956,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                        json_object_object_add(json_route, "backupNexthops",
                                               json_nexthops);
                }
+               zebra_show_ip_route_opaque(NULL, re, json_route);
 
                json_object_array_add(json, json_route);
                return;
@@ -1274,8 +1304,11 @@ DEFPY (show_ip_nht,
                VRF_GET_ID(vrf_id, vrf_name, false);
 
        memset(&prefix, 0, sizeof(prefix));
-       if (addr)
+       if (addr) {
                p = sockunion2hostprefix(addr, &prefix);
+               if (!p)
+                       return CMD_WARNING;
+       }
 
        zebra_print_rnh_table(vrf_id, afi, vty, rtype, p);
        return CMD_SUCCESS;
@@ -1298,7 +1331,7 @@ DEFUN (ip_nht_default_route,
 
        zvrf->zebra_rnh_ip_default_route = 1;
 
-       zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL);
+       zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_NEXTHOP_TYPE, NULL);
        return CMD_SUCCESS;
 }
 
@@ -1620,7 +1653,7 @@ DEFUN (no_ip_nht_default_route,
                return CMD_SUCCESS;
 
        zvrf->zebra_rnh_ip_default_route = 0;
-       zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL);
+       zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_NEXTHOP_TYPE, NULL);
        return CMD_SUCCESS;
 }
 
@@ -1640,7 +1673,7 @@ DEFUN (ipv6_nht_default_route,
                return CMD_SUCCESS;
 
        zvrf->zebra_rnh_ipv6_default_route = 1;
-       zebra_evaluate_rnh(zvrf, AFI_IP6, 1, RNH_NEXTHOP_TYPE, NULL);
+       zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_NEXTHOP_TYPE, NULL);
        return CMD_SUCCESS;
 }
 
@@ -1662,7 +1695,7 @@ DEFUN (no_ipv6_nht_default_route,
                return CMD_SUCCESS;
 
        zvrf->zebra_rnh_ipv6_default_route = 0;
-       zebra_evaluate_rnh(zvrf, AFI_IP6, 1, RNH_NEXTHOP_TYPE, NULL);
+       zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_NEXTHOP_TYPE, NULL);
        return CMD_SUCCESS;
 }
 
@@ -1960,9 +1993,6 @@ DEFPY (show_route_summary,
        struct route_table *table;
        bool uj = use_json(argc, argv);
 
-       if (table_id == 0)
-               table_id = RT_TABLE_MAIN;
-
        if (vrf_all) {
                struct vrf *vrf;
                struct zebra_vrf *zvrf;
@@ -1971,8 +2001,13 @@ DEFPY (show_route_summary,
                        if ((zvrf = vrf->info) == NULL)
                                continue;
 
-                       table = zebra_vrf_lookup_table_with_table_id(
-                               afi, SAFI_UNICAST, zvrf->vrf->vrf_id, table_id);
+                       if (table_id == 0)
+                               table = zebra_vrf_table(afi, SAFI_UNICAST,
+                                                       zvrf->vrf->vrf_id);
+                       else
+                               table = zebra_vrf_lookup_table_with_table_id(
+                                       afi, SAFI_UNICAST, zvrf->vrf->vrf_id,
+                                       table_id);
 
                        if (!table)
                                continue;
@@ -1989,8 +2024,11 @@ DEFPY (show_route_summary,
                if (vrf_name)
                        VRF_GET_ID(vrf_id, vrf_name, false);
 
-               table = zebra_vrf_lookup_table_with_table_id(afi, SAFI_UNICAST,
-                                                            vrf_id, table_id);
+               if (table_id == 0)
+                       table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id);
+               else
+                       table = zebra_vrf_lookup_table_with_table_id(
+                               afi, SAFI_UNICAST, vrf_id, table_id);
                if (!table)
                        return CMD_SUCCESS;
 
@@ -2494,6 +2532,20 @@ DEFPY (evpn_mh_startup_delay,
                        no ? true : false);
 }
 
+DEFPY(evpn_mh_redirect_off, evpn_mh_redirect_off_cmd,
+      "[no$no] evpn mh redirect-off",
+      NO_STR
+      "EVPN\n"
+      "Multihoming\n"
+      "ES bond redirect for fast-failover off\n")
+{
+       bool redirect_off;
+
+       redirect_off = no ? false : true;
+
+       return zebra_evpn_mh_redirect_off(vty, redirect_off);
+}
+
 DEFUN (default_vrf_vni_mapping,
        default_vrf_vni_mapping_cmd,
        "vni " CMD_VNI_RANGE "[prefix-routes-only]",
@@ -2673,6 +2725,21 @@ DEFUN (show_evpn_global,
        return CMD_SUCCESS;
 }
 
+DEFPY(show_evpn_l2_nh,
+      show_evpn_l2_nh_cmd,
+      "show evpn l2-nh [json$json]",
+      SHOW_STR
+      "EVPN\n"
+      "Layer2 nexthops\n"
+      JSON_STR)
+{
+       bool uj = !!json;
+
+       zebra_evpn_l2_nh_show(vty, uj);
+
+       return CMD_SUCCESS;
+}
+
 DEFPY(show_evpn_es,
       show_evpn_es_cmd,
       "show evpn es [NAME$esi_str|detail$detail] [json$json]",
@@ -2680,8 +2747,8 @@ DEFPY(show_evpn_es,
       "EVPN\n"
       "Ethernet Segment\n"
       "ES ID\n"
-      JSON_STR
-      "Detailed information\n")
+      "Detailed information\n"
+      JSON_STR)
 {
        esi_t esi;
        bool uj = !!json;
@@ -4020,6 +4087,7 @@ void zebra_vty_init(void)
        install_element(VIEW_NODE, &show_evpn_vni_cmd);
        install_element(VIEW_NODE, &show_evpn_vni_detail_cmd);
        install_element(VIEW_NODE, &show_evpn_vni_vni_cmd);
+       install_element(VIEW_NODE, &show_evpn_l2_nh_cmd);
        install_element(VIEW_NODE, &show_evpn_es_cmd);
        install_element(VIEW_NODE, &show_evpn_es_evi_cmd);
        install_element(VIEW_NODE, &show_evpn_access_vlan_cmd);
@@ -4052,6 +4120,7 @@ void zebra_vty_init(void)
        install_element(CONFIG_NODE, &evpn_mh_mac_holdtime_cmd);
        install_element(CONFIG_NODE, &evpn_mh_neigh_holdtime_cmd);
        install_element(CONFIG_NODE, &evpn_mh_startup_delay_cmd);
+       install_element(CONFIG_NODE, &evpn_mh_redirect_off_cmd);
        install_element(CONFIG_NODE, &default_vrf_vni_mapping_cmd);
        install_element(CONFIG_NODE, &no_default_vrf_vni_mapping_cmd);
        install_element(VRF_NODE, &vrf_vni_mapping_cmd);
index 4b3b142d4024bb804cee1a903edff68b61343310..697a6eecf14a3fd7ba375593fd8ed1e4ea09bfbf 100644 (file)
@@ -116,7 +116,12 @@ static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
                                struct in_addr mcast_grp);
 static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
                                struct in_addr mcast_grp);
-static void zebra_vxlan_sg_cleanup(struct hash_bucket *bucket, void *arg);
+static void zebra_vxlan_cleanup_sg_table(struct zebra_vrf *zvrf);
+
+bool zebra_evpn_do_dup_addr_detect(struct zebra_vrf *zvrf)
+{
+       return zvrf->dup_addr_detect && zebra_evpn_mh_do_dup_addr_detect();
+}
 
 /* Private functions */
 static int host_rb_entry_compare(const struct host_rb_entry *hle1,
@@ -1987,7 +1992,10 @@ static void zevpn_add_to_l3vni_list(struct hash_bucket *bucket, void *ctxt)
 }
 
 /*
- *  handle transition of vni from l2 to l3 and vice versa
+ * Handle transition of vni from l2 to l3 and vice versa.
+ * This function handles only the L2VNI add/delete part of
+ * the above transition.
+ * L3VNI add/delete is handled by the calling functions.
  */
 static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
                                             int add)
@@ -2028,11 +2036,71 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
                        return -1;
                }
        } else {
-               /* TODO_MITESH: This needs to be thought through. We don't have
-                * enough information at this point to reprogram the vni as
-                * l2-vni. One way is to store the required info in l3-vni and
-                * used it solely for this purpose
-                */
+               struct zebra_ns *zns;
+               struct route_node *rn;
+               struct interface *ifp;
+               struct zebra_if *zif;
+               struct zebra_l2info_vxlan *vxl;
+               struct interface *vlan_if;
+               bool found = false;
+
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("Adding L2-VNI %u - transition from L3-VNI",
+                                  vni);
+
+               /* Find VxLAN interface for this VNI. */
+               zns = zebra_ns_lookup(NS_DEFAULT);
+               for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+                       ifp = (struct interface *)rn->info;
+                       if (!ifp)
+                               continue;
+                       zif = ifp->info;
+                       if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+                               continue;
+
+                       vxl = &zif->l2info.vxl;
+                       if (vxl->vni == vni) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (!found) {
+                       if (IS_ZEBRA_DEBUG_VXLAN)
+                               zlog_err(
+                                       "Adding L2-VNI - Failed to find VxLAN interface for VNI %u",
+                                       vni);
+                       return -1;
+               }
+
+               /* Create VNI hash entry for L2VNI */
+               zevpn = zebra_evpn_lookup(vni);
+               if (zevpn)
+                       return 0;
+
+               zevpn = zebra_evpn_add(vni);
+               if (!zevpn) {
+                       flog_err(EC_ZEBRA_VNI_ADD_FAILED,
+                                "Adding L2-VNI - Failed to add VNI hash, VNI %u",
+                                vni);
+
+                       return -1;
+               }
+
+               /* Find bridge interface for the VNI */
+               vlan_if = zvni_map_to_svi(vxl->access_vlan,
+                                         zif->brslave_info.br_if);
+               if (vlan_if)
+                       zevpn->vrf_id = vlan_if->vrf_id;
+
+               zevpn->vxlan_if = ifp;
+               zevpn->local_vtep_ip = vxl->vtep_ip;
+
+               /* Inform BGP if the VNI is up and mapped to a bridge. */
+               if (if_is_operative(ifp) && zif->brslave_info.br_if) {
+                       zebra_evpn_send_add_to_client(zevpn);
+                       zebra_evpn_read_mac_neigh(zevpn, ifp);
+               }
        }
 
        return 0;
@@ -3417,7 +3485,7 @@ void zebra_vxlan_print_evpn(struct vty *vty, bool uj)
                json_object_int_add(json, "numVnis", num_vnis);
                json_object_int_add(json, "numL2Vnis", num_l2vnis);
                json_object_int_add(json, "numL3Vnis", num_l3vnis);
-               if (zvrf->dup_addr_detect)
+               if (zebra_evpn_do_dup_addr_detect(zvrf))
                        json_object_boolean_true_add(json,
                                                "isDuplicateAddrDetection");
                else
@@ -3436,7 +3504,8 @@ void zebra_vxlan_print_evpn(struct vty *vty, bool uj)
                vty_out(vty, "Advertise svi mac-ip: %s\n",
                        zvrf->advertise_svi_macip ? "Yes" : "No");
                vty_out(vty, "Duplicate address detection: %s\n",
-                       zvrf->dup_addr_detect ? "Enable" : "Disable");
+                       zebra_evpn_do_dup_addr_detect(zvrf) ? "Enable"
+                                                           : "Disable");
                vty_out(vty, "  Detection max-moves %u, time %d\n",
                        zvrf->dad_max_moves, zvrf->dad_time);
                if (zvrf->dad_freeze) {
@@ -3505,6 +3574,7 @@ void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS)
        uint32_t freeze_time = 0;
        bool dup_addr_detect = false;
        bool freeze = false;
+       bool old_addr_detect;
 
        s = msg;
        STREAM_GETL(s, dup_addr_detect);
@@ -3513,13 +3583,16 @@ void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS)
        STREAM_GETL(s, freeze);
        STREAM_GETL(s, freeze_time);
 
+       old_addr_detect = zebra_evpn_do_dup_addr_detect(zvrf);
+       zvrf->dup_addr_detect = dup_addr_detect;
+       dup_addr_detect = zebra_evpn_do_dup_addr_detect(zvrf);
+
        /* DAD previous state was enabled, and new state is disable,
         * clear all duplicate detected addresses.
         */
-       if (zvrf->dup_addr_detect && !dup_addr_detect)
+       if (old_addr_detect && !dup_addr_detect)
                zebra_vxlan_clear_dup_detect_vni_all(zvrf);
 
-       zvrf->dup_addr_detect = dup_addr_detect;
        zvrf->dad_time = time;
        zvrf->dad_max_moves = max_moves;
        zvrf->dad_freeze = freeze;
@@ -3529,9 +3602,8 @@ void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS)
                zlog_debug(
                        "VRF %s duplicate detect %s max_moves %u timeout %u freeze %s freeze_time %u",
                        vrf_id_to_name(zvrf->vrf->vrf_id),
-                       zvrf->dup_addr_detect ? "enable" : "disable",
-                       zvrf->dad_max_moves,
-                       zvrf->dad_time,
+                       dup_addr_detect ? "enable" : "disable",
+                       zvrf->dad_max_moves, zvrf->dad_time,
                        zvrf->dad_freeze ? "enable" : "disable",
                        zvrf->dad_freeze_time);
 
@@ -3669,13 +3741,13 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp,
 
        if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
                zlog_debug(
-                       "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s%s%s-> L2-VNI %u",
+                       "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s%s%s%s-> L2-VNI %u",
                        ipaddr2str(ip, buf2, sizeof(buf2)),
                        prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
                        ifp->ifindex, state, is_ext ? "ext-learned " : "",
                        is_router ? "router " : "",
                        local_inactive ? "local_inactive " : "",
-                       zevpn->vni);
+                       dp_static ? "peer_sync " : "", zevpn->vni);
 
        /* Is this about a local neighbor or a remote one? */
        if (!is_ext)
@@ -3901,9 +3973,10 @@ int zebra_vxlan_check_readd_vtep(struct interface *ifp,
  * us, this must involve a multihoming scenario. Treat this as implicit delete
  * of any prior local MAC.
  */
-int zebra_vxlan_check_del_local_mac(struct interface *ifp,
-                                   struct interface *br_if,
-                                   struct ethaddr *macaddr, vlanid_t vid)
+static int zebra_vxlan_check_del_local_mac(struct interface *ifp,
+                                          struct interface *br_if,
+                                          struct ethaddr *macaddr,
+                                          vlanid_t vid)
 {
        struct zebra_if *zif;
        struct zebra_l2info_vxlan *vxl;
@@ -3960,14 +4033,48 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
        return 0;
 }
 
+/* MAC notification from the dataplane with a network dest port -
+ * 1. This can be a local MAC on a down ES (if fast-failover is not possible
+ * 2. Or it can be a remote MAC
+ */
+int zebra_vxlan_dp_network_mac_add(struct interface *ifp,
+                                  struct interface *br_if,
+                                  struct ethaddr *macaddr, vlanid_t vid,
+                                  uint32_t nhg_id, bool sticky, bool dp_static)
+{
+       struct zebra_evpn_es *es;
+       struct interface *acc_ifp;
+
+       /* if remote mac delete the local entry */
+       if (!nhg_id || !zebra_evpn_nhg_is_local_es(nhg_id, &es)
+           || !zebra_evpn_es_local_mac_via_network_port(es)) {
+               if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+                       zlog_debug("dpAdd remote MAC %pEA VID %u", macaddr,
+                                  vid);
+               return zebra_vxlan_check_del_local_mac(ifp, br_if, macaddr,
+                                                      vid);
+       }
+
+       /* If local MAC on a down local ES translate the network-mac-add
+        * to a local-inactive-mac-add
+        */
+       if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               zlog_debug("dpAdd local-nw-MAC %pEA VID %u", macaddr, vid);
+       acc_ifp = es->zif->ifp;
+       return zebra_vxlan_local_mac_add_update(
+               acc_ifp, br_if, macaddr, vid, sticky,
+               false /* local_inactive */, dp_static);
+}
+
 /*
- * Handle remote MAC delete by kernel; readd the remote MAC if we have it.
- * This can happen because the remote MAC entries are also added as "dynamic",
- * so the kernel can ageout the entry.
+ * Handle network MAC delete by kernel -
+ * 1. readd the remote MAC if we have it
+ * 2. local MAC with does ES may also need to be re-installed
  */
-int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
-                                      struct interface *br_if,
-                                      struct ethaddr *macaddr, vlanid_t vid)
+static int zebra_vxlan_do_local_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac);
+int zebra_vxlan_dp_network_mac_del(struct interface *ifp,
+                                  struct interface *br_if,
+                                  struct ethaddr *macaddr, vlanid_t vid)
 {
        struct zebra_if *zif = NULL;
        struct zebra_l2info_vxlan *vxl = NULL;
@@ -3975,7 +4082,6 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
        zebra_evpn_t *zevpn = NULL;
        zebra_l3vni_t *zl3vni = NULL;
        zebra_mac_t *mac = NULL;
-       char buf[ETHER_ADDR_STRLEN];
 
        zif = ifp->info;
        assert(zif);
@@ -4001,16 +4107,89 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
        if (!mac)
                return 0;
 
-       /* Is it a remote entry? */
-       if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
-               return 0;
+       if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
+               /* If remote entry simply re-install */
+               if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+                       zlog_debug(
+                               "dpDel remote MAC %pEA intf %s(%u) VNI %u - readd",
+                               macaddr, ifp->name, ifp->ifindex, vni);
+               zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */);
+       } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) && mac->es
+                  && zebra_evpn_es_local_mac_via_network_port(mac->es)) {
+               /* If local entry via nw-port call local-del which will
+                * re-install entry in the dataplane is needed
+                */
+               if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+                       zlog_debug("dpDel local-nw-MAC %pEA VNI %u", macaddr,
+                                  vni);
+               zebra_vxlan_do_local_mac_del(zevpn, mac);
+       }
+
+       return 0;
+}
+
+static int zebra_vxlan_do_local_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac)
+{
+       bool old_bgp_ready;
+       bool new_bgp_ready;
 
        if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug("Del remote MAC %s intf %s(%u) VNI %u - readd",
-                          prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
-                          ifp->ifindex, vni);
+               zlog_debug("DEL MAC %pEA VNI %u seq %u flags 0x%x nbr count %u",
+                          &mac->macaddr, zevpn->vni, mac->loc_seq, mac->flags,
+                          listcount(mac->neigh_list));
+
+       old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
+       if (zebra_evpn_mac_is_static(mac)) {
+               /* this is a synced entry and can only be removed when the
+                * es-peers stop advertising it.
+                */
+               memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+                       zlog_debug(
+                               "re-add sync-mac vni %u mac %pEA es %s seq %d f 0x%x",
+                               zevpn->vni, &mac->macaddr,
+                               mac->es ? mac->es->esi_str : "-", mac->loc_seq,
+                               mac->flags);
+
+               /* inform-bgp about change in local-activity if any */
+               if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
+                       SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
+                       new_bgp_ready =
+                               zebra_evpn_mac_is_ready_for_bgp(mac->flags);
+                       zebra_evpn_mac_send_add_del_to_client(
+                               mac, old_bgp_ready, new_bgp_ready);
+               }
+
+               /* re-install the entry in the kernel */
+               zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
+                                              false /* force_clear_static */,
+                                              __func__);
+
+               return 0;
+       }
+
+       /* Update all the neigh entries associated with this mac */
+       zebra_evpn_process_neigh_on_local_mac_del(zevpn, mac);
+
+       /* Remove MAC from BGP. */
+       zebra_evpn_mac_send_del_to_client(zevpn->vni, &mac->macaddr, mac->flags,
+                                         false /* force */);
+
+       zebra_evpn_es_mac_deref_entry(mac);
+
+       /*
+        * If there are no neigh associated with the mac delete the mac
+        * else mark it as AUTO for forward reference
+        */
+       if (!listcount(mac->neigh_list)) {
+               zebra_evpn_mac_del(zevpn, mac);
+       } else {
+               UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
+               UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
+               SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+       }
 
-       zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */);
        return 0;
 }
 
@@ -4021,6 +4200,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
                              struct ethaddr *macaddr, vlanid_t vid)
 {
        zebra_evpn_t *zevpn;
+       zebra_mac_t *mac;
 
        /* We are interested in MACs only on ports or (port, VLAN) that
         * map to a VNI.
@@ -4035,7 +4215,16 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
                return -1;
        }
 
-       return zebra_evpn_del_local_mac(zevpn, macaddr, ifp);
+       /* If entry doesn't exist, nothing to do. */
+       mac = zebra_evpn_mac_lookup(zevpn, macaddr);
+       if (!mac)
+               return 0;
+
+       /* Is it a local entry? */
+       if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
+               return 0;
+
+       return zebra_vxlan_do_local_mac_del(zevpn, mac);
 }
 
 /*
@@ -5075,6 +5264,7 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
 
        if (add) {
 
+               /* Remove L2VNI if present */
                zebra_vxlan_handle_vni_transition(zvrf, vni, add);
 
                /* check if the vni is already present under zvrf */
@@ -5169,6 +5359,7 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
                zvrf->l3vni = 0;
                zl3vni_del(zl3vni);
 
+               /* Add L2VNI for this VNI */
                zebra_vxlan_handle_vni_transition(zvrf, vni, add);
        }
        return 0;
@@ -5658,7 +5849,7 @@ void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf)
        if (!zvrf)
                return;
        hash_iterate(zvrf->evpn_table, zebra_evpn_vxlan_cleanup_all, zvrf);
-       hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_cleanup, NULL);
+       zebra_vxlan_cleanup_sg_table(zvrf);
 
        if (zvrf == evpn_zvrf)
                zebra_evpn_es_cleanup();
@@ -5671,6 +5862,11 @@ void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
                return;
        hash_iterate(zvrf->evpn_table, zebra_evpn_vxlan_cleanup_all, zvrf);
        hash_free(zvrf->evpn_table);
+       if (zvrf->vxlan_sg_table) {
+               zebra_vxlan_cleanup_sg_table(zvrf);
+               hash_free(zvrf->vxlan_sg_table);
+               zvrf->vxlan_sg_table = NULL;
+       }
 }
 
 /* init the l3vni table */
@@ -5919,6 +6115,30 @@ static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
        zebra_vxlan_sg_do_ref(zvrf, local_vtep_ip, mcast_grp);
 }
 
+static void zebra_vxlan_xg_pre_cleanup(struct hash_bucket *backet, void *arg)
+{
+       zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
+
+       /* increment the ref count against (*,G) to prevent them from being
+        * deleted
+        */
+       if (vxlan_sg->sg.src.s_addr == INADDR_ANY)
+               ++vxlan_sg->ref_cnt;
+}
+
+static void zebra_vxlan_xg_post_cleanup(struct hash_bucket *backet, void *arg)
+{
+       zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
+
+       /* decrement the dummy ref count against (*,G) to delete them */
+       if (vxlan_sg->sg.src.s_addr == INADDR_ANY) {
+               if (vxlan_sg->ref_cnt)
+                       --vxlan_sg->ref_cnt;
+               if (!vxlan_sg->ref_cnt)
+                       zebra_vxlan_sg_del(vxlan_sg);
+       }
+}
+
 static void zebra_vxlan_sg_cleanup(struct hash_bucket *backet, void *arg)
 {
        zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
@@ -5926,6 +6146,19 @@ static void zebra_vxlan_sg_cleanup(struct hash_bucket *backet, void *arg)
        zebra_vxlan_sg_del(vxlan_sg);
 }
 
+static void zebra_vxlan_cleanup_sg_table(struct zebra_vrf *zvrf)
+{
+       /* increment the ref count against (*,G) to prevent them from being
+        * deleted
+        */
+       hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_xg_pre_cleanup, NULL);
+
+       hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_cleanup, NULL);
+
+       /* decrement the dummy ref count against the XG entries */
+       hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_xg_post_cleanup, NULL);
+}
+
 static void zebra_vxlan_sg_replay_send(struct hash_bucket *backet, void *arg)
 {
        zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
index 534e29936d5b6c05b4cedd6afe5e0e735b336e58..24de8ff04ee1f814de96979b20fcfdab8333e597 100644 (file)
@@ -177,13 +177,6 @@ extern int zebra_vxlan_local_mac_add_update(struct interface *ifp,
 extern int zebra_vxlan_local_mac_del(struct interface *ifp,
                                     struct interface *br_if,
                                     struct ethaddr *mac, vlanid_t vid);
-extern int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
-                                             struct interface *br_if,
-                                             struct ethaddr *mac,
-                                             vlanid_t vid);
-extern int zebra_vxlan_check_del_local_mac(struct interface *ifp,
-                                          struct interface *br_if,
-                                          struct ethaddr *mac, vlanid_t vid);
 extern int zebra_vxlan_check_readd_vtep(struct interface *ifp,
                                        struct in_addr vtep_ip);
 extern int zebra_vxlan_if_up(struct interface *ifp);
@@ -222,6 +215,15 @@ extern void zebra_evpn_init(void);
 extern void zebra_vxlan_macvlan_up(struct interface *ifp);
 extern void zebra_vxlan_macvlan_down(struct interface *ifp);
 extern int vni_list_cmp(void *p1, void *p2);
+extern int zebra_vxlan_dp_network_mac_add(struct interface *ifp,
+                                         struct interface *br_if,
+                                         struct ethaddr *macaddr, vlanid_t vid,
+                                         uint32_t nhg_id, bool sticky,
+                                         bool dp_static);
+extern int zebra_vxlan_dp_network_mac_del(struct interface *ifp,
+                                         struct interface *br_if,
+                                         struct ethaddr *macaddr,
+                                         vlanid_t vid);
 
 #ifdef __cplusplus
 }
index 9a88d98b81817e9943912a9827a980e7babfb4fd..4ec55542a7255ca0a2fd9c0b8e8edf2cc3fceb7a 100644 (file)
@@ -258,5 +258,6 @@ typedef struct zebra_vxlan_sg_ {
 extern zebra_evpn_t *zevpn_lookup(vni_t vni);
 extern void zebra_vxlan_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
                bool force_clear_static, const char *caller);
+extern bool zebra_evpn_do_dup_addr_detect(struct zebra_vrf *zvrf);
 
 #endif /* _ZEBRA_VXLAN_PRIVATE_H */
index 4b5791530d0868ea774f6dddcae5a60c6853422a..484d94fac881a7c0a2d8178f6f7e1d4345c7f1d4 100644 (file)
@@ -1033,6 +1033,9 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
        } else
                vty_out(vty, "Not registered for Nexthop Updates\n");
 
+       vty_out(vty, "Client will %sbe notified about it's routes status\n",
+               client->notify_owner ? "" : "Not ");
+
        last_read_time = (time_t)atomic_load_explicit(&client->last_read_time,
                                                      memory_order_relaxed);
        last_write_time = (time_t)atomic_load_explicit(&client->last_write_time,
@@ -1300,6 +1303,21 @@ DEFUN (show_zebra_client_summary,
        return CMD_SUCCESS;
 }
 
+static int zserv_client_close_cb(struct zserv *closed_client)
+{
+       struct listnode *node, *nnode;
+       struct zserv *client = NULL;
+
+       for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+               if (client->proto == closed_client->proto)
+                       continue;
+
+               zsend_client_close_notify(client, closed_client);
+       }
+
+       return 0;
+}
+
 void zserv_init(void)
 {
        /* Client list init. */
@@ -1312,4 +1330,6 @@ void zserv_init(void)
 
        install_element(ENABLE_NODE, &show_zebra_client_cmd);
        install_element(ENABLE_NODE, &show_zebra_client_summary_cmd);
+
+       hook_register(zserv_client_close, zserv_client_close_cb);
 }